def flatten(self, obj):
        """Recursively iterate through this signature, retrieving member values from an interface
        object.

        .. note::

            The :ref:`paths <wiring-path>` returned by this method and by
            :meth:`SignatureMembers.flatten` differ. This method yield several results for each
            :class:`Member` in the collection that has a dimension:

            .. doctest::
                :options: +NORMALIZE_WHITESPACE

                >>> sig = wiring.Signature({
                ...     "items": In(1).array(2)
                ... })
                >>> obj = sig.create()
                >>> list(sig.flatten(obj))
                [(('items', 0), In(1), (sig obj__items__0)),
                 (('items', 1), In(1), (sig obj__items__1))]

            The :meth:`SignatureMembers.flatten` method yields one result for such a member; see
            the documentation for that method for an example.

        Returns
        -------
        iterator of (:class:`tuple` of :class:`str` or :class:`int`, :class:`Flow`, :ref:`value-like <lang-valuelike>`)
            Tuples of :ref:`paths <wiring-path>`, flow, and the corresponding member values. A path
            yielded by this method is a tuple of strings or integers where each item is an attribute
            name or index (correspondingly) using which the member value was retrieved.
        """
        for name, member in self.members.items():
            path = (name,)
            value = getattr(obj, name)

            def iter_member(value, *, path):
                if member.is_port:
                    yield path, Member(member.flow, member.shape, init=member.init), value
                elif member.is_signature:
                    for sub_path, sub_member, sub_value in member.signature.flatten(value):
                        yield ((*path, *sub_path), sub_member, sub_value)
                else:
                    assert False # :nocov:

            def iter_dimensions(value, dimensions, *, path):
                if not dimensions:
                    yield from iter_member(value, path=path)
                else:
                    dimension, *rest_of_dimensions = dimensions
                    for index in range(dimension):
                        yield from iter_dimensions(value[index], rest_of_dimensions,
                                                   path=(*path, index))

            yield from iter_dimensions(value, dimensions=member.dimensions, path=path)
Recursively iterate through this signature, retrieving member values from an interface
        object.

        .. note::

            The :ref:`paths <wiring-path>` returned by this method and by
            :meth:`SignatureMembers.flatten` differ. This method yield several results for each
            :class:`Member` in the collection that has a dimension:

            .. doctest::
                :options: +NORMALIZE_WHITESPACE

                >>> sig = wiring.Signature({
                ...     "items": In(1).array(2)
                ... })
                >>> obj = sig.create()
                >>> list(sig.flatten(obj))
                [(('items', 0), In(1), (sig obj__items__0)),
                 (('items', 1), In(1), (sig obj__items__1))]

            The :meth:`SignatureMembers.flatten` method yields one result for such a member; see
            the documentation for that method for an example.

        Returns
        -------
        iterator of (:class:`tuple` of :class:`str` or :class:`int`, :class:`Flow`, :ref:`value-like <lang-valuelike>`)
            Tuples of :ref:`paths <wiring-path>`, flow, and the corresponding member values. A path
            yielded by this method is a tuple of strings or integers where each item is an attribute
            name or index (correspondingly) using which the member value was retrieved.
        
amaranth/lib/wiring.py