Skip to main content

finite_set

Macro finite_set 

Source
macro_rules! finite_set {
    (
        $(#[$name_meta:meta])*
        $name:ident,
        $(#[$table_meta:meta])*
        $table:ident {
            $($(#[$variant_meta:meta])* $variant:ident $(= $value:tt)? as $field:tt),+ $(,)?
        }
    ) => { ... };
    (
        $(#[$name_meta:meta])*
        $name:ident,
        $(#[$table_meta:meta])*
        $table:ident {
            $($(#[$variant_meta:meta])* $variant:ident $(= $value:tt)? as $field:tt),+ $(,)?
        },
        $cursor:ident
    ) => { ... };
    (
        $(#[$name_meta:meta])*
        $name:ident,
        $(#[$record_meta:meta])*
        $record:ident,
        $(#[$table_meta:meta])*
        $table:ident,
        {
            $($(#[$variant_meta:meta])* $variant:ident $(= $value:tt)? as $field:ident),+ $(,)?
        }
    ) => { ... };
    (
        @table
        $len:expr,
        { $(#[$name_meta:meta])* },
        $name:ident,
        { $(#[$table_meta:meta])* },
        $table:ident,
        $table_expr:ident {
            $($(#[$variant_meta:meta])* $variant:ident $(= $value:tt)? as $field:tt),+ $(,)?
        }
    ) => { ... };
    (
        @record
        $len:expr,
        { $(#[$name_meta:meta])* },
        $name:ident,
        { $(#[$record_meta:meta])* },
        $record:ident,
        { $(#[$table_meta:meta])* },
        $table:ident,
        {
            $($(#[$variant_meta:meta])* $variant:ident $(= $value:tt)? as $field:ident),+ $(,)?
        }
    ) => { ... };
    (
        @cursor
        $len:expr,
        $name:ident,
        $cursor:ident
    ) => { ... };
    (@count $($variant:ident),+) => { ... };
    (@unit $variant:ident) => { ... };
    (@name $field:ident) => { ... };
    (@name $field:literal) => { ... };
}
Expand description

Defines a small finite enum, its table type, and optionally its record type.

This macro keeps enum-indexed tables usable in const contexts. It works around current Rust const-fn limitations by generating inherent const helpers instead of relying only on trait methods and indexing operators.

Every variant must have an as label. The label becomes the canonical string returned by name() and written by Display.

Table-only form:

finite_set!(
    /// Board square.
    Square,
    /// Array-backed table keyed by square.
    SquareTable {
        /// Lower-left square from White's perspective.
        A1 = 0 as a1,
        B1 = 1 as b1,
    }
);

Table-only form with cursor:

finite_set!(
    File,
    FileTable {
        A = 0 as a,
        B = 1 as b,
    },
    FileCursor
);

Attributes are optional at every documented position. Values are optional when the previous variant’s discriminant plus one is the desired value:

finite_set!(Square, SquareTable {
    A1 = 0 as a1,
    B1 as b1,
});

Record form:

finite_set!(
    /// Player to move / piece owner.
    Player,
    /// Named-field values keyed by player.
    Players,
    /// Array-backed table keyed by player.
    PlayerTable,
    {
        /// Black player.
        Black = 0 as black,
        /// White player.
        White = 1 as white,
    }
);

The generated enum gets:

  • ALL and LEN
  • name, eq, index, from_index, and panicky_from_index
  • iter and iter_rev
  • Display via name

The generated table type is an alias for Table and gets key-based indexing plus get, get_ref, and get_mut.

The record form also generates a named-field struct with the same key-based indexing and accessors.

The public arms calculate the enum length with @count, then dispatch to private arms. @table emits the enum, FiniteSet, and the array-backed table alias. @record first delegates to @table, then adds the named-field record and its indexing helpers.