# Enumerations

The `amaranth.lib.enum` module is a drop-in replacement for the standard `enum` module that provides extended `Enum`, `IntEnum`, `Flag`, and `IntFlag` classes with the ability to specify a shape explicitly.

A shape can be specified for an enumeration with the `shape=` keyword argument:

    from amaranth.lib import enum

    class Funct(enum.Enum, shape=4):
        ADD = 0
        SUB = 1
        MUL = 2

    >>> Shape.cast(Funct)
    unsigned(4)
    >>> Value.cast(Funct.ADD)
    (const 4'd0)

Any constant-castable expression can be used as the value of a member:

    class Op(enum.Enum, shape=1):
        REG = 0
        IMM = 1

    class Instr(enum.Enum, shape=5):
        ADD  = Cat(Funct.ADD, Op.REG)
        ADDI = Cat(Funct.ADD, Op.IMM)
        SUB  = Cat(Funct.SUB, Op.REG)
        SUBI = Cat(Funct.SUB, Op.IMM)
        ...

    >>> Instr.SUBI
    <Instr.SUBI: 17>

The `shape=` argument is optional. If not specified, classes from this module behave exactly the same as classes from the standard `enum` module, and likewise, this module re-exports everything exported by the standard `enum` module.

    import amaranth.lib.enum

    class NormalEnum(amaranth.lib.enum.Enum):
        SPAM = 0
        HAM  = 1

In this way, this module is a drop-in replacement for the standard `enum` module, and in an Amaranth project, all `import enum` statements may be replaced with `from amaranth.lib import enum`.

Signals with `Enum` or `Flag` based shape are automatically wrapped in the `EnumView` or `FlagView` value-like wrappers, which ensure type safety. Any value-like can also be explicitly wrapped in a view class by casting it to the enum type:

    >>> a = Signal(Funct)
    >>> b = Signal(Op)
    >>> type(a)
    <class 'amaranth.lib.enum.EnumView'>
    >>> a == b
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: an EnumView can only be compared to value or other EnumView of the same enum type
    >>> c = Signal(4)
    >>> type(Funct(c))
    <class 'amaranth.lib.enum.EnumView'>

Like the standard Python `enum.IntEnum` and `enum.IntFlag` classes, the Amaranth `IntEnum` and `IntFlag` classes are loosely typed and will not be subject to wrapping in view classes:

    class TransparentEnum(enum.IntEnum, shape=unsigned(4)):
        FOO = 0
        BAR = 1

    >>> a = Signal(TransparentEnum)
    >>> type(a) is Signal
    True

It is also possible to define a custom view class for a given enum:

    class InstrView(enum.EnumView):
        def has_immediate(self):
            return (self == Instr.ADDI) | (self == Instr.SUBI)

    class Instr(enum.Enum, shape=5, view_class=InstrView):
        ADD  = Cat(Funct.ADD, Op.REG)
        ADDI = Cat(Funct.ADD, Op.IMM)
        SUB  = Cat(Funct.SUB, Op.REG)
        SUBI = Cat(Funct.SUB, Op.IMM)

    >>> a = Signal(Instr)
    >>> type(a)
    <class 'InstrView'>
    >>> a.has_immediate()
    (| (== (sig a) (const 5'd16)) (== (sig a) (const 5'd17)))

## Metaclass

class amaranth.lib.enum.EnumType

  Subclass of the standard `enum.EnumType` that implements the `ShapeCastable` protocol.

  This metaclass provides the `as_shape()` method, making its instances shape-like, and accepts a `shape=` keyword argument to specify a shape explicitly. Other than this, it acts the same as the standard `enum.EnumType` class; if the `shape=` argument is not specified and `as_shape()` is never called, it places no restrictions on the enumeration class or the values of its members.

  When a value-like is cast to an enum type that is an instance of this metaclass, it can be automatically wrapped in a view class. A custom view class can be specified by passing the `view_class=` keyword argument when creating the enum class.

  as_shape()

    Cast this enumeration to a shape.

    Returns:

      Explicitly provided shape. If not provided, returns the result of shape-casting this class as a standard Python enumeration.

    Return type:

      `Shape`

    Raises:

      TypeError – If the enumeration has neither an explicitly provided shape nor any members.

  __call__(value, *args, **kwargs)

    Cast the value to this enum type.

    When given an integer constant, it returns the corresponding enum value, like a standard Python enumeration.

    When given a value-like, it is cast to a value, then wrapped in the `view_class` specified for this enum type (`EnumView` for `Enum`, `FlagView` for `Flag`, or a custom user-defined class). If the type has no `view_class` (like `IntEnum` or `IntFlag`), a plain `Value` is returned.

    Returns:

      - instance of itself – For integer values, or instances of itself.

      - `EnumView` or its subclass – For value-castables, as defined by the `view_class` keyword argument.

      - `Value` – For value-castables, when a view class is not specified for this enum.

## Base classes

class amaranth.lib.enum.Enum

  Subclass of the standard `enum.Enum` that has `EnumType` as its metaclass and `EnumView` as its view class.

class amaranth.lib.enum.IntEnum

  Subclass of the standard `enum.IntEnum` that has `EnumType` as its metaclass.

class amaranth.lib.enum.Flag

  Subclass of the standard `enum.Flag` that has `EnumType` as its metaclass and `FlagView` as its view class.

class amaranth.lib.enum.IntFlag

  Subclass of the standard `enum.IntFlag` that has `EnumType` as its metaclass.

## View classes

class amaranth.lib.enum.EnumView

  The view class used for `Enum`.

  Wraps a `Value` and only allows type-safe operations. The only operators allowed are equality comparisons (`==` and `!=`) with another `EnumView` of the same enum type.

  __init__(enum, target)

    Constructs a view with the given enum type and target (a value-like).

  shape()

    Returns the underlying enum type.

  as_value()

    Returns the underlying value.

  eq(other)

    Assign to the underlying value.

    Returns:

      `self.as_value().eq(other)`

    Return type:

      `Assign`

  __eq__(other)

    Compares the underlying value for equality.

    The other operand has to be either another `EnumView` with the same enum type, or a plain value of the underlying enum.

    Returns:

      The result of the equality comparison, as a single-bit value.

    Return type:

      `Value`

class amaranth.lib.enum.FlagView

  The view class used for `Flag`.

  In addition to the operations allowed by `EnumView`, it allows bitwise operations among values of the same enum type.

  __invert__()

    Inverts all flags in this value and returns another `FlagView`.

    Note that this is not equivalent to applying bitwise negation to the underlying value: just like the Python `enum.Flag` class, only bits corresponding to flags actually defined in the enumeration are included in the result.

    Return type:

      `FlagView`

  __and__(other)

    Performs a bitwise AND and returns another `FlagView`.

    The other operand has to be either another `FlagView` of the same enum type, or a plain value of the underlying enum type.

    Return type:

      `FlagView`

  __or__(other)

    Performs a bitwise OR and returns another `FlagView`.

    The other operand has to be either another `FlagView` of the same enum type, or a plain value of the underlying enum type.

    Return type:

      `FlagView`

  __xor__(other)

    Performs a bitwise XOR and returns another `FlagView`.

    The other operand has to be either another `FlagView` of the same enum type, or a plain value of the underlying enum type.

    Return type:

      `FlagView`

  __rand__(other)

    Performs a bitwise AND and returns another `FlagView`.

    The other operand has to be either another `FlagView` of the same enum type, or a plain value of the underlying enum type.

    Return type:

      `FlagView`

  __ror__(other)

    Performs a bitwise OR and returns another `FlagView`.

    The other operand has to be either another `FlagView` of the same enum type, or a plain value of the underlying enum type.

    Return type:

      `FlagView`

  __rxor__(other)

    Performs a bitwise XOR and returns another `FlagView`.

    The other operand has to be either another `FlagView` of the same enum type, or a plain value of the underlying enum type.

    Return type:

      `FlagView`