"""
This type stub file was generated by pyright.
"""

import enum
from collections.abc import Iterable, Mapping, Iterator
from typing import NoReturn, Literal, TypeVar, Generic, Any, Self, Optional, overload
from ..hdl._ir import Elaboratable
from .._utils import final
from amaranth_types import ShapeLike, ValueLike, AbstractInterface, AbstractSignature, ModuleLike
from .meta import Annotation

__all__ = ["In", "Out", "Signature", "PureInterface", "connect", "flipped", "Component"]

_T_Signature = TypeVar("_T_Signature", bound=AbstractSignature)
_T_SignatureMembers = TypeVar("_T_SignatureMembers", bound=SignatureMembers)
_T_Interface = TypeVar("_T_Interface", bound=AbstractInterface)
_T = TypeVar("_T")

class Flow(enum.Enum):
    """Direction of data flow. This enumeration has two values, :attr:`Out` and :attr:`In`,
    the meaning of which depends on the context in which they are used.
    """
    Out = "out"
    In = "in"
    def flip(self) -> Flow:
        """Flip the direction of data flow.

        Returns
        -------
        :class:`Flow`
            :attr:`In` if called as :pc:`Out.flip()`; :attr:`Out` if called as :pc:`In.flip()`.
        """
        ...
    
    def __call__(self, description: AbstractSignature | ShapeLike, *, reset=...) -> Member:
        """Create a :class:`Member` with this data flow and the provided description and
        reset value.

        Returns
        -------
        :class:`Member`
            :pc:`Member(self, description, reset=reset)`
        """
        ...
    
    def __repr__(self) -> Literal['Out', 'In']:
        ...
    
    def __str__(self) -> str:
        ...
    


Out = Flow.Out
In = Flow.In

@final
class Member:
    """Description of a signature member.

    This class is a discriminated union: its instances describe either a `port member` or
    a `signature member`, and accessing properties for the wrong kind of member raises
    an :exc:`AttributeError`.

    The class is created from a `description`: a :class:`Signature` instance (in which case
    the :class:`Member` is created as a signature member), or a :ref:`shape-like <lang-shapelike>`
    object (in which case it is created as a port member). After creation the :class:`Member`
    instance cannot be modified.

    When a :class:`Signal` is created from a description of a port member, the signal's reset value
    is taken from the member description. If this signal is never explicitly assigned a value, it
    will equal ``reset``.

    Although instances can be created directly, most often they will be created through
    :data:`In` and :data:`Out`, e.g. :pc:`In(unsigned(1))` or :pc:`Out(stream.Signature(RGBPixel))`.
    """
    def __init__(self, flow: Flow, description: AbstractSignature | ShapeLike, *, reset=..., _dimensions=...) -> None:
        ...
    
    def flip(self) -> Member:
        """Flip the data flow of this member.

        Returns
        -------
        :class:`Member`
            A new :pc:`member` with :pc:`member.flow` equal to :pc:`self.flow.flip()`, and identical
            to :pc:`self` other than that.
        """
        ...
    
    def array(self, *dimensions) -> Member:
        """Add array dimensions to this member.

        The dimensions passed to this method are `prepended` to the existing dimensions.
        For example, :pc:`Out(1).array(2)` describes an array of 2 elements, whereas both
        :pc:`Out(1).array(2, 3)` and :pc:`Out(1).array(3).array(2)` both describe a two dimensional
        array of 2 by 3 elements.

        Dimensions are passed to :meth:`array` in the order in which they would be indexed.
        That is, :pc:`.array(x, y)` creates a member that can be indexed up to :pc:`[x-1][y-1]`.

        The :meth:`array` method is composable: calling :pc:`member.array(x)` describes an array of
        :pc:`x` members even if :pc:`member` was already an array.

        Returns
        -------
        :class:`Member`
            A new :pc:`member` with :pc:`member.dimensions` extended by :pc:`dimensions`, and
            identical to :pc:`self` other than that.
        """
        ...
    
    @property
    def flow(self) -> Flow:
        """Data flow of this member.

        Returns
        -------
        :class:`Flow`
        """
        ...
    
    @property
    def is_port(self) -> bool:
        """Whether this is a description of a port member.

        Returns
        -------
        :class:`bool`
            :pc:`True` if this is a description of a port member,
            :pc:`False` if this is a description of a signature member.
        """
        ...
    
    @property
    def is_signature(self) -> bool:
        """Whether this is a description of a signature member.

        Returns
        -------
        :class:`bool`
            :pc:`True` if this is a description of a signature member,
            :pc:`False` if this is a description of a port member.
        """
        ...
    
    @property
    def shape(self) -> ShapeLike:
        """Shape of a port member.

        Returns
        -------
        :ref:`shape-like object <lang-shapelike>`
            The shape that was provided when constructing this :class:`Member`.

        Raises
        ------
        :exc:`AttributeError`
            If :pc:`self` describes a signature member.
        """
        ...
    
    @property
    def reset(self): # -> None:
        """Reset value of a port member.

        Returns
        -------
        :ref:`const-castable object <lang-constcasting>`
            The reset value that was provided when constructing this :class:`Member`.

        Raises
        ------
        :exc:`AttributeError`
            If :pc:`self` describes a signature member.
        """
        ...
    
    @property
    def signature(self) -> AbstractSignature:
        """Signature of a signature member.

        Returns
        -------
        :class:`Signature`
            The signature that was provided when constructing this :class:`Member`.

        Raises
        ------
        :exc:`AttributeError`
            If :pc:`self` describes a port member.
        """
        ...
    
    @property
    def dimensions(self) -> tuple[int, ...]:
        """Array dimensions.

        A member will usually have no dimensions; in this case it does not describe an array.
        A single dimension describes one-dimensional array, and so on.

        Returns
        -------
        :class:`tuple` of :class:`int`
            Dimensions, if any, of this member, from most to least major.
        """
        ...
    
    def __eq__(self, other) -> bool:
        ...
    
    def __repr__(self) -> str:
        ...
    


@final
class SignatureError(Exception):
    """
    This exception is raised when an invalid operation specific to signature manipulation is
    performed with :class:`SignatureMembers`, such as adding a member to a frozen signature.
    Other exceptions, such as :exc:`TypeError` or :exc:`NameError`, will still be raised where
    appropriate.
    """
    ...


@final
class SignatureMembers(Mapping[str, Member]):
    """Mapping of signature member names to their descriptions.

    This container, a :class:`collections.abc.Mapping`, is used to implement the :pc:`members`
    attribute of signature objects.

    The keys in this container must be valid Python attribute names that are public (do not begin
    with an underscore. The values must be instances of :class:`Member`. The container is mutable
    in a restricted manner: new keys may be added, but existing keys may not be modified or removed.
    In addition, the container can be `frozen`, which disallows addition of new keys. Freezing
    a container recursively freezes the members of any signatures inside.

    In addition to the use of the superscript operator, multiple members can be added at once with
    the :pc:`+=` opreator.

    The :meth:`create` method converts this mapping into a mapping of names to signature members
    (signals and interface objects) by creating them from their descriptions. The created mapping
    can be used to populate an interface object.
    """
    def __init__(self, members: Mapping[str, Member]=...) -> None:
        ...
    
    def flip(self) -> FlippedSignatureMembers[Self]:
        """Flip the data flow of the members in this mapping.

        Returns
        -------
        :class:`FlippedSignatureMembers`
            Proxy collection :pc:`FlippedSignatureMembers(self)` that flips the data flow of
            the members that are accessed using it.
        """
        ...
    
    def __eq__(self, other) -> bool:
        """Compare the members in this and another mapping.

        Returns
        -------
        :class:`bool`
            :pc:`True` if the mappings contain the same key-value pairs, :pc:`False` otherwise.
        """
        ...
    
    def __contains__(self, name: str) -> bool:
        """Check whether a member with a given name exists.

        Returns
        -------
        :class:`bool`
        """
        ...
    
    def __getitem__(self, name: str) -> Member:
        """Retrieves the description of a member with a given name.

        Returns
        -------
        :class:`Member`

        Raises
        ------
        :exc:`TypeError`
            If :pc:`name` is not a string.
        :exc:`NameError`
            If :pc:`name` is not a valid, public Python attribute name.
        :exc:`SignatureError`
            If a member called :pc:`name` does not exist in the collection.
        """
        ...
    
    def __setitem__(self, name: str, member: Member) -> NoReturn:
        """Stub that forbids addition of members to the collection.

        Raises
        ------
        :exc:`SignatureError`
            Always.
        """
        ...
    
    def __delitem__(self, name: str) -> NoReturn:
        """Stub that forbids removal of members from the collection.

        Raises
        ------
        :exc:`SignatureError`
            Always.
        """
        ...
    
    def __iter__(self) -> Iterator[str]:
        """Iterate through the names of members in the collection.

        Returns
        -------
        iterator of :class:`str`
            Names of members, in the order of insertion.
        """
        ...
    
    def __len__(self) -> int:
        ...
    
    def flatten(self, *, path: tuple[str | int, ...]=...) -> Iterator[tuple[tuple[str | int, ...], Member]]:
        """Recursively iterate through this collection.

        .. note::

            The :ref:`paths <wiring-path>` returned by this method and by :meth:`Signature.flatten`
            differ. This method yields a single result for each :class:`Member` in the collection,
            disregarding their dimensions:

            .. doctest::

                >>> sig = wiring.Signature({
                ...     "items": In(1).array(2)
                ... })
                >>> list(sig.members.flatten())
                [(('items',), In(1).array(2))]

            The :meth:`Signature.flatten` method yields multiple results for such a member; see
            the documentation for that method for an example.

        Returns
        -------
        iterator of (:class:`tuple` of :class:`str`, :class:`Member`)
            Pairs of :ref:`paths <wiring-path>` and the corresponding members. A path yielded by
            this method is a tuple of strings where each item is a key through which the item may
            be reached.
        """
        ...
    
    def create(self, *, path: tuple[str | int, ...] =..., src_loc_at: int =...) -> dict[str, Any]:
        """Create members from their descriptions.

        For each port member, this function creates a :class:`Signal` with the shape and reset
        value taken from the member description, and the name constructed from
        the :ref:`paths <wiring-path>` to the member (by concatenating path items with a double
        underscore, ``__``).

        For each signature member, this function calls :meth:`Signature.create` for that signature.
        The resulting object can have any type if a :class:`Signature` subclass overrides
        the :class:`create` method.

        If the member description includes dimensions, in each case, instead of a single member,
        a :class:`list` of members is created for each dimension. (That is, for a single dimension
        a list of members is returned, for two dimensions a list of lists is returned, and so on.)

        Returns
        -------
        dict of :class:`str` to :ref:`value-like <lang-valuelike>` or interface object or a potentially nested list of these
            Mapping of names to actual signature members.
        """
        ...
    
    def __repr__(self) -> str:
        ...
    


@final
class FlippedSignatureMembers(Mapping[str, Member], Generic[_T_SignatureMembers]):
    """Mapping of signature member names to their descriptions, with the directions flipped.

    Although an instance of :class:`FlippedSignatureMembers` could be created directly, it will
    be usually created by a call to :meth:`SignatureMembers.flip`.

    This container is a wrapper around :class:`SignatureMembers` that contains the same members
    as the inner mapping, but flips their data flow when they are accessed. For example:

    .. testcode::

        members = wiring.SignatureMembers({"foo": Out(1)})

        flipped_members = members.flip()
        assert flipped_members["foo"].flow == In

    This class implements the same methods, with the same functionality (other than the flipping of
    the data flow), as the :class:`SignatureMembers` class; see the documentation for that class
    for details.
    """
    def __init__(self, unflipped: _T_SignatureMembers) -> None:
        ...
    
    def flip(self) -> _T_SignatureMembers:
        """
        Flips this mapping back to the original one.

        Returns
        -------
        :class:`SignatureMembers`
            :pc:`unflipped`
        """
        ...
    
    def __eq__(self, other) -> bool:
        """Compare the members in this and another mapping.

        Returns
        -------
        :class:`bool`
            :pc:`True` if the mappings contain the same key-value pairs, :pc:`False` otherwise.
        """
        ...
    
    def __contains__(self, name: str) -> bool:
        ...
    
    def __getitem__(self, name: str) -> Member:
        ...
    
    def __setitem__(self, name: str, member: Member) -> NoReturn:
        ...
    
    def __delitem__(self, name: str) -> NoReturn:
        ...
    
    def __iter__(self) -> Iterator[str]:
        ...
    
    def __len__(self) -> int:
        ...
    
    def flatten(self, *, path: tuple[str | int, ...] = ...) -> Iterator[tuple[tuple[str | int, ...], Member]]:
        """Recursively iterate through this collection.

        .. note::

            The :ref:`paths <wiring-path>` returned by this method and by :meth:`Signature.flatten`
            differ. This method yields a single result for each :class:`Member` in the collection,
            disregarding their dimensions:

            .. doctest::

                >>> sig = wiring.Signature({
                ...     "items": In(1).array(2)
                ... })
                >>> list(sig.members.flatten())
                [(('items',), In(1).array(2))]

            The :meth:`Signature.flatten` method yields multiple results for such a member; see
            the documentation for that method for an example.

        Returns
        -------
        iterator of (:class:`tuple` of :class:`str`, :class:`Member`)
            Pairs of :ref:`paths <wiring-path>` and the corresponding members. A path yielded by
            this method is a tuple of strings where each item is a key through which the item may
            be reached.
        """
        ...
    
    def create(self, *, path: tuple[str | int, ...] =..., src_loc_at: int =...) -> dict[str, Any]:
        """Create members from their descriptions.

        For each port member, this function creates a :class:`Signal` with the shape and reset
        value taken from the member description, and the name constructed from
        the :ref:`paths <wiring-path>` to the member (by concatenating path items with a double
        underscore, ``__``).

        For each signature member, this function calls :meth:`Signature.create` for that signature.
        The resulting object can have any type if a :class:`Signature` subclass overrides
        the :class:`create` method.

        If the member description includes dimensions, in each case, instead of a single member,
        a :class:`list` of members is created for each dimension. (That is, for a single dimension
        a list of members is returned, for two dimensions a list of lists is returned, and so on.)

        Returns
        -------
        dict of :class:`str` to :ref:`value-like <lang-valuelike>` or interface object or a potentially nested list of these
            Mapping of names to actual signature members.
        """
        ...
    
    def __repr__(self) -> str:
        ...
    


class SignatureMeta(type):
    """Metaclass for :class:`Signature` that makes :class:`FlippedSignature` its
    'virtual subclass'.

    The object returned by :meth:`Signature.flip` is an instance of :class:`FlippedSignature`.
    It implements all of the methods :class:`Signature` has, and for subclasses of
    :class:`Signature`, it implements all of the methods defined on the subclass as well.
    This makes it effectively a subtype of :class:`Signature` (or a derived class of it), but this
    relationship is not captured by the Python type system: :class:`FlippedSignature` only has
    :class:`object` as its base class.

    This metaclass extends :func:`issubclass` and :func:`isinstance` so that they take into
    account the subtyping relationship between :class:`Signature` and :class:`FlippedSignature`,
    described below.
    """
    def __subclasscheck__(cls, subclass) -> bool:
        """
        Override of :pc:`issubclass(cls, Signature)`.

        In addition to the standard behavior of :func:`issubclass`, this override makes
        :class:`FlippedSignature` a subclass of :class:`Signature` or any of its subclasses.
        """
        ...
    
    def __instancecheck__(cls, instance) -> bool:
        """
        Override of :pc:`isinstance(obj, Signature)`.

        In addition to the standard behavior of :func:`isinstance`, this override makes
        :pc:`isinstance(obj, cls)` act as :pc:`isinstance(obj.flip(), cls)` where
        :pc:`obj` is an instance of :class:`FlippedSignature`.
        """
        ...
    


class Signature(metaclass=SignatureMeta):
    """Description of an interface object.

    An interface object is a Python object that has a :pc:`signature` attribute containing
    a :class:`Signature` object, as well as an attribute for every member of its signature.
    Signatures and interface objects are tightly linked: an interface object can be created out
    of a signature, and the signature is used when :func:`connect` ing two interface objects
    together. See the :ref:`introduction to interfaces <wiring-intro1>` for a more detailed
    explanation of why this is useful.

    :class:`Signature` can be used as a base class to define :ref:`customized <wiring-customizing>`
    signatures and interface objects.

    .. important::

        :class:`Signature` objects are immutable. Classes inheriting from :class:`Signature` must
        ensure this remains the case when additional functionality is added.
    """
    def __init__(self, members: Mapping[str, Member]) -> None:
        ...
    
    def flip(self) -> FlippedSignature[Self]:
        """Flip the data flow of the members in this signature.

        Returns
        -------
        :class:`FlippedSignature`
            Proxy object :pc:`FlippedSignature(self)` that flips the data flow of the attributes
            corresponding to the members that are accessed using it.

            See the documentation for the :class:`FlippedSignature` class for a detailed discussion
            of how this proxy object works.
        """
        ...
    
    @property
    def members(self) -> SignatureMembers:
        """Members in this signature.

        Returns
        -------
        :class:`SignatureMembers`
        """
        ...
    
    def __eq__(self, other) -> bool:
        """Compare this signature with another.

        The behavior of this operator depends on the types of the arguments. If both :pc:`self`
        and :pc:`other` are instances of the base :class:`Signature` class, they are compared
        structurally (the result is :pc:`self.members == other.members`); otherwise they are
        compared by identity (the result is :pc:`self is other`).

        Subclasses of :class:`Signature` are expected to override this method to take into account
        the specifics of the domain. If the subclass has additional properties that do not influence
        the :attr:`members` dictionary but nevertheless make its instance incompatible with other
        instances (for example, whether the feedback is combinational or registered),
        the overridden method must take that into account.

        Returns
        -------
        :class:`bool`
        """
        ...
    
    def flatten(self, obj) -> Iterator[tuple[tuple[str | int, ...], Flow, ValueLike]]:
        """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.
        """
        ...
    
    def is_compliant(self, obj, *, reasons: Optional[list[str]] =..., path: tuple[str, ...] =...) -> bool:
        """Check whether an object matches the description in this signature.

        This module places few restrictions on what an interface object may be; it does not
        prescribe a specific base class or a specific way of constructing the object, only
        the values that its attributes should have. This method ensures consistency between
        the signature and the interface object, checking every aspect of the provided interface
        object for compliance with the signature.

        It verifies that:

        * :pc:`obj` has a :pc:`signature` attribute whose value a :class:`Signature` instance
          such that ``self == obj.signature``;
        * for each member, :pc:`obj` has an attribute with the same name, whose value:

          * for members with :meth:`dimensions <Member.dimensions>` specified, contains a list or
            a tuple (or several levels of nested lists or tuples, for multiple dimensions)
            satisfying the requirements below;
          * for port members, is a :ref:`value-like <lang-valuelike>` object casting to
            a :class:`Signal` or a :class:`Const` whose width and signedness is the same as that
            of the member, and (in case of a :class:`Signal`) which is not reset-less and whose
            reset value is that of the member;
          * for signature members, matches the description in the signature as verified by
            :meth:`Signature.is_compliant`.

        If the verification fails, this method reports the reason(s) by filling the :pc:`reasons`
        container. These reasons are intended to be human-readable: more than one reason may be
        reported but only in cases where this is helpful (e.g. the same error message will not
        repeat 10 times for each of the 10 ports in a list).

        Arguments
        ---------
        reasons : :class:`list` or :pc:`None`
            If provided, a container that receives diagnostic messages.
        path : :class:`tuple` of :class:`str`
            The :ref:`path <wiring-path>` to :pc:`obj`. Could be set to improve diagnostic
            messages if :pc:`obj` is nested within another object, or for clarity.

        Returns
        -------
        :class:`bool`
            :pc:`True` if :pc:`obj` matches the description in this signature, :pc:`False`
            otherwise. If :pc:`False` and :pc:`reasons` was not :pc:`None`, it will contain
            a detailed explanation why.
        """
        ...
    
    def create(self, *, path: tuple[str | int, ...]=..., src_loc_at: int =...) -> AbstractInterface[Self]:
        """Create an interface object from this signature.

        The default :meth:`Signature.create` implementation consists of one line:

        .. code::

            def create(self, *, path=None, src_loc_at=0):
                return PureInterface(self, path=path, src_loc_at=1 + src_loc_at)

        This implementation creates an interface object from this signature that serves purely
        as a container for the attributes corresponding to the signature members, and implements
        no behavior. Such an implementation is sufficient for signatures created ad-hoc using
        the :pc:`Signature({ ... })` constructor as well as simple signature subclasses.

        When defining a :class:`Signature` subclass that needs to customize the behavior of
        the created interface objects, override this method with a similar implementation
        that references the class of your custom interface object:

        .. testcode::

            class CustomSignature(wiring.Signature):
                def create(self, *, path=None, src_loc_at=0):
                    return CustomInterface(self, path=path, src_loc_at=1 + src_loc_at)

            class CustomInterface(wiring.PureInterface):
                @property
                def my_property(self):
                    ...

        The :pc:`path` and :pc:`src_loc_at` arguments are necessary to ensure the generated signals
        have informative names and accurate source location information.

        The custom :meth:`create` method may take positional or keyword arguments in addition to
        the two listed above. Such arguments must have a default value, because
        the :meth:`SignatureMembers.create` method will call the :meth:`Signature.create` member
        without these additional arguments when this signature is a member of another signature.
        """
        ...

    def annotations(self, obj: AbstractInterface[Self], /) -> Iterable[Annotation]:
        ...

    def __repr__(self) -> str:
        ...
    


@final
class FlippedSignature(Generic[_T_Signature]):
    """Description of an interface object, with the members' directions flipped.

    Although an instance of :class:`FlippedSignature` could be created directly, it will be usually
    created by a call to :meth:`Signature.flip`.

    This proxy is a wrapper around :class:`Signature` that contains the same description as
    the inner mapping, but flips the members' data flow when they are accessed. It is useful
    because :class:`Signature` objects are mutable and may include custom behavior, and if one was
    copied (rather than wrapped) by :meth:`Signature.flip`, the wrong object would be mutated, and
    custom behavior would be unavailable.

    For example:

    .. testcode::

        sig = wiring.Signature({"foo": Out(1)})

        flipped_sig = sig.flip()
        assert flipped_sig.members["foo"].flow == In

        sig.attr = 1
        assert flipped_sig.attr == 1
        flipped_sig.attr += 1
        assert sig.attr == flipped_sig.attr == 2

    This class implements the same methods, with the same functionality (other than the flipping of
    the members' data flow), as the :class:`Signature` class; see the documentation for that class
    for details.

    It is not possible to inherit from :class:`FlippedSignature` and :meth:`Signature.flip` must not
    be overridden. If a :class:`Signature` subclass defines a method and this method is called on
    a flipped instance of the subclass, it receives the flipped instance as its :pc:`self` argument.
    To distinguish being called on the flipped instance from being called on the unflipped one, use
    :pc:`isinstance(self, FlippedSignature)`:

    .. testcode::

        class SignatureKnowsWhenFlipped(wiring.Signature):
            @property
            def is_flipped(self):
                return isinstance(self, wiring.FlippedSignature)

        sig = SignatureKnowsWhenFlipped({})
        assert sig.is_flipped == False
        assert sig.flip().is_flipped == True
    """
    def __init__(self, signature: _T_Signature) -> None:
        ...
    
    def flip(self) -> _T_Signature:
        """
        Flips this signature back to the original one.

        Returns
        -------
        :class:`Signature`
            :pc:`unflipped`
        """
        ...
    
    @property
    def members(self) -> FlippedSignatureMembers:
        ...
    
    def __eq__(self, other) -> bool:
        ...
    
    def flatten(self, obj) -> Iterator[tuple[tuple[str | int, ...], Flow, ValueLike]]:
        ...

    def is_compliant(self, obj, *, reasons: Optional[list[str]] =..., path: tuple[str, ...] =...) -> bool:
        ...

    def __getattr__(self, name) -> Any:
        """Retrieves attribute or method :pc:`name` of the unflipped signature.

        Performs :pc:`getattr(unflipped, name)`, ensuring that, if :pc:`name` refers to a property
        getter or a method, its :pc:`self` argument receives the *flipped* signature. A class
        method's :pc:`cls` argument receives the class of the *unflipped* signature, as usual.
        """
        ...
    
    def __setattr__(self, name, value) -> None:
        """Assigns attribute :pc:`name` of the unflipped signature to ``value``.

        Performs :pc:`setattr(unflipped, name, value)`, ensuring that, if :pc:`name` refers to
        a property setter, its :pc:`self` argument receives the flipped signature.
        """
        ...
    
    def __delattr__(self, name) -> None:
        """Removes attribute :pc:`name` of the unflipped signature.

        Performs :pc:`delattr(unflipped, name)`, ensuring that, if :pc:`name` refers to a property
        deleter, its :pc:`self` argument receives the flipped signature.
        """
        ...
    
    def create(self, *args, path: tuple[str | int, ...] =..., src_loc_at: int =..., **kwargs) -> FlippedInterface:
        ...
    
    def __repr__(self) -> str:
        ...
    


class PureInterface(Generic[_T_Signature]):
    """A helper for constructing ad-hoc interfaces.

    The :class:`PureInterface` helper primarily exists to be used by the default implementation of
    :meth:`Signature.create`, but it can also be used in any other context where an interface
    object needs to be created without the overhead of defining a class for it.

    .. important::

        Any object can be an interface object; it only needs a :pc:`signature` property containing
        a compliant signature. It is **not** necessary to use :class:`PureInterface` in order to
        create an interface object, but it may be used either directly or as a base class whenever
        it is convenient to do so.
    """
    signature: _T_Signature

    def __init__(self, signature: _T_Signature, *, path: tuple[str | int, ...]=..., src_loc_at: int =...) -> None:
        """Create attributes from a signature.

        The sole method defined by this helper is its constructor, which only defines
        the :pc:`self.signature` attribute as well as the attributes created from the signature
        members:

        .. code::

            def __init__(self, signature, *, path):
                self.__dict__.update({
                    "signature": signature,
                    **signature.members.create(path=path)
                })

        .. note::

            This implementation can be copied and reused in interface objects that *do* include
            custom behavior, if the signature serves as the source of truth for attributes
            corresponding to its members. Although it is less repetitive, this approach can confuse
            IDEs and type checkers.
        """
        ...
    
    def __repr__(self) -> str:
        ...
    


@final
class FlippedInterface(Generic[_T_Signature, _T_Interface]):
    """An interface object, with its members' directions flipped.

    An instance of :class:`FlippedInterface` should only be created by calling :func:`flipped`,
    which ensures that a :pc:`FlippedInterface(FlippedInterface(...))` object is never created.

    This proxy wraps any interface object and forwards attribute and method access to the wrapped
    interface object while flipping its signature and the values of any attributes corresponding to
    interface members. It is useful because interface objects may be mutable or include custom
    behavior, and explicitly keeping track of whether the interface object is flipped would be very
    burdensome.

    For example:

    .. testcode::

        intf = wiring.PureInterface(wiring.Signature({"foo": Out(1)}), path=())

        flipped_intf = wiring.flipped(intf)
        assert flipped_intf.signature.members["foo"].flow == In

        intf.attr = 1
        assert flipped_intf.attr == 1
        flipped_intf.attr += 1
        assert intf.attr == flipped_intf.attr == 2

    It is not possible to inherit from :class:`FlippedInterface`. If an interface object class
    defines a method or a property and it is called on the flipped interface object, the method
    receives the flipped interface object as its :pc:`self` argument. To distinguish being called
    on the flipped interface object from being called on the unflipped one, use
    :pc:`isinstance(self, FlippedInterface)`:

    .. testcode::

        class InterfaceKnowsWhenFlipped:
            signature = wiring.Signature({})

            @property
            def is_flipped(self):
                return isinstance(self, wiring.FlippedInterface)

        intf = InterfaceKnowsWhenFlipped()
        assert intf.is_flipped == False
        assert wiring.flipped(intf).is_flipped == True
    """
    def __init__(self, interface: _T_Interface) -> None:
        ...

    # not true -- this is a property -- but required for clean typing
    signature: _T_Signature
#    @property
#    def signature(self) -> _T_Signature:
#        """Signature of the flipped interface.
#
#        Returns
#        -------
#        Signature
#            :pc:`unflipped.signature.flip()`
#        """
#        ...
    
    def __eq__(self, other) -> bool:
        """Compare this flipped interface with another.

        Returns
        -------
        bool
            :pc:`True` if :pc:`other` is an instance :pc:`FlippedInterface(other_unflipped)` where
            :pc:`unflipped == other_unflipped`, :pc:`False` otherwise.
        """
        ...
    
    def __getattr__(self, name) -> Any:
        """Retrieves attribute or method :pc:`name` of the unflipped interface.

        Performs :pc:`getattr(unflipped, name)`, with the following caveats:

        1. If :pc:`name` refers to a signature member, the returned interface object is flipped.
        2. If :pc:`name` refers to a property getter or a method, its :pc:`self` argument receives
           the *flipped* interface. A class method's :pc:`cls` argument receives the class of
           the *unflipped* interface, as usual.
        """
        ...
    
    def __setattr__(self, name, value) -> None:
        """Assigns attribute :pc:`name` of the unflipped interface to ``value``.

        Performs :pc:`setattr(unflipped, name, value)`, with the following caveats:

        1. If :pc:`name` refers to a signature member, the assigned interface object is flipped.
        2. If :pc:`name` refers to a property setter, its :pc:`self` argument receives the flipped
           interface.
        """
        ...
    
    def __delattr__(self, name) -> None:
        """Removes attribute :pc:`name` of the unflipped interface.

        Performs :pc:`delattr(unflipped, name)`, ensuring that, if :pc:`name` refers to a property
        deleter, its :pc:`self` argument receives the flipped interface.
        """
        ...
    
    def __repr__(self) -> str:
        ...
    
@overload
def flipped(interface: FlippedInterface[_T_Signature, _T_Interface]) -> _T_Interface:
    ...

# Can't be typed nicer for now.
@overload
def flipped(interface: _T_Interface) -> FlippedInterface[Any, _T_Interface]:
    ...

def flipped(interface: _T_Interface) -> _T_Interface | FlippedInterface[Any, _T_Interface]:
    """
    Flip the data flow of the members of the interface object :pc:`interface`.

    If an interface object is flipped twice, returns the original object:
    :pc:`flipped(flipped(interface)) is interface`. Otherwise, wraps :pc:`interface` in
    a :class:`FlippedInterface` proxy object that flips the directions of its members.

    See the documentation for the :class:`FlippedInterface` class for a detailed discussion of how
    this proxy object works.
    """
    ...

@final
class ConnectionError(Exception):
    """Exception raised when the :func:`connect` function is requested to perform an impossible,
    meaningless, or forbidden connection."""
    ...


def connect(m: ModuleLike, *args: AbstractInterface, **kwargs: AbstractInterface) -> None:
    """Connect interface objects to each other.

    This function creates connections between ports of several interface objects. (Any number of
    interface objects may be provided; in most cases it is two.)

    The connections can be made only if all of the objects satisfy a number of requirements:

    * Every interface object must have the same set of port members, and they must have the same
      :meth:`dimensions <Member.dimensions>`.
    * For each path, the port members of every interface object must have the same width and reset
      value (for port members corresponding to signals) or constant value (for port members
      corresponding to constants). Signedness may differ.
    * For each path, at most one interface object must have the corresponding port member be
      an output.
    * For a given path, if any of the interface objects has an input port member corresponding
      to a constant value, then the rest of the interface objects must have output port members
      corresponding to the same constant value.

    For example, if :pc:`obj1` is being connected to :pc:`obj2` and :pc:`obj3`, and :pc:`obj1.a.b`
    is an output, then :pc:`obj2.a.b` and :pc:`obj2.a.b` must exist and be inputs. If :pc:`obj2.c`
    is an input and its value is :pc:`Const(1)`, then :pc:`obj1.c` and :pc:`obj3.c` must be outputs
    whose value is also :pc:`Const(1)`. If no ports besides :pc:`obj1.a.b` and :pc:`obj1.c` exist,
    then no ports except for those two must exist on :pc:`obj2` and :pc:`obj3` either.

    Once it is determined that the interface objects can be connected, this function performs
    an equivalent of:

    .. code::

        m.d.comb += [
            in1.eq(out1),
            in2.eq(out1),
            ...
        ]

    Where :pc:`out1` is an output and :pc:`in1`, :pc:`in2`, ... are the inputs that have the same
    path. (If no interface object has an output for a given path, **no connection at all** is made.)

    The positions (within :pc:`args`) or names (within :pc:`kwargs`) of the arguments do not affect
    the connections that are made. There is no difference in behavior between :pc:`connect(m, a, b)`
    and :pc:`connect(m, b, a)` or :pc:`connect(m, arbiter=a, decoder=b)`. The names of the keyword
    arguments serve only a documentation purpose: they clarify the diagnostic messages when
    a connection cannot be made.
    """
    ...

class Component(Elaboratable, Generic[_T_Signature]):
    """Base class for elaboratable interface objects.

    A component is an :class:`Elaboratable` whose interaction with other parts of the design is
    defined by its signature. Most if not all elaboratables in idiomatic Amaranth code should be
    components, as the signature clarifies the direction of data flow at their boundary. See
    the :ref:`introduction to interfaces <wiring-intro1>` section for a practical guide to defining
    and using components.

    There are two ways to define a component. If all instances of a component have the same
    signature, it can be defined using :term:`variable annotations <python:variable annotation>`:

    .. testcode::

        class FixedComponent(wiring.Component):
            en: In(1)
            data: Out(8)

    The variable annotations are collected by the constructor :meth:`Component.__init__`. Only
    public (not starting with ``_``) annotations with :class:`In <Member>` or :class:`Out <Member>`
    objects are considered; all other annotations are ignored under the assumption that they are
    interpreted by some other tool.

    It is possible to use inheritance to extend a component: the component's signature is composed
    from the variable annotations in the class that is being constructed as well as all of its
    base classes. It is an error to have more than one variable annotation for the same attribute.

    If different instances of a component may need to have different signatures, variable
    annotations cannot be used. In this case, the constructor should be overridden, and
    the computed signature members should be provided to the superclass constructor:

    .. testcode::

        class ParametricComponent(wiring.Component):
            def __init__(self, data_width):
                super().__init__({
                    "en": In(1),
                    "data": Out(data_width)
                })

    It is also possible to pass a :class:`Signature` instance to the superclass constructor.

    Aside from initializing the :attr:`signature` attribute, the :meth:`Component.__init__`
    constructor creates attributes corresponding to all of the members defined in the signature.
    If an attribute with the same name as that of a member already exists, an error is raied.

    Raises
    ------
    :exc:`TypeError`
        If the :pc:`signature` object is neither a :class:`Signature` nor a :class:`dict`.
        If neither variable annotations nor the :pc:`signature` argument are present, or if
        both are present.
    :exc:`NameError`
        If a name conflict is detected between two variable annotations, or between a member
        and an existing attribute.
    """
    def __init__(self, signature: Optional[_T_Signature | dict[str, Member]] = None) -> None:
        ...
    
    @property
    def signature(self) -> _T_Signature:
        """The signature of the component.

        .. important::

            Do not override this property. Once a component is constructed, its :attr:`signature`
            property must always return the same :class:`Signature` instance. The constructor
            can be used to customize a component's signature.
        """
        ...

    @property
    def metadata(self) -> ComponentMetadata:
        """Metadata attached to the component.
        
        Returns
        -------
        :class:`ComponentMetadata`
        """
        ...


class InvalidMetadata(Exception):
    """Exception raised by :meth:`ComponentMetadata.validate` when the JSON representation of
    a component's metadata does not conform to its schema."""


class ComponentMetadata(Annotation[Component]):
    def __init__(self, origin: Component):
        ...

    @property
    def origin(self) -> Component:
        ...

    @classmethod
    def validate(cls, instance: dict) -> None:
        ...

    def as_json(self) -> dict:
        ...
