strum

repository·master·Indexed 25 days ago

https://github.com/peternator7/strum

A collection of Rust macros and traits for working with enums and strings. It provides procedural macros to augment enums with string representations, metadata, and utility functions, including EnumString for string-to-enum conversion, Display for enum-to-string conversion, EnumIter for iterating over variants, and FromRepr for converting integers to enums.

Tokens
5.5K
Snippets
16
Records
24
Agent score
82%

What's inside strum

  1. Include Strum in your project

    master

    To use Strum, add it to your Cargo.toml. You can either import strum and strum_macros separately, or use the derive feature on the strum crate to import the macros directly from strum.

    [dependencies]
    strum = "0.28"
    strum_macros = "0.28"
    
    # Alternatively, use the derive feature to import macros directly from strum:
    # strum = { version = "0.28", features = ["derive"] }
  2. Use `EnumDiscriminants` to generate a discriminant enum

    master

    The EnumDiscriminants derive macro (part of the strum crate) automatically generates a new enum containing only the variants of your original enum, effectively acting as a collection of its discriminants.

    Key Behaviors:

    • Naming: By default, the new enum is named {OriginalName}Discriminants. You can customize this using the #[strum_discriminants(name = "...")] attribute on the original enum.
    • Visibility: The generated enum inherits the visibility of the original enum unless specified otherwise via #[strum_discriminants(vis = "...")].
    • Attributes: Certain attributes like #[doc], #[cfg], #[allow], and #[deny] are automatically copied from the original variants to the new discriminant variants.
    • Default Variant: If any variant in your original enum is marked with #[default], the generated discriminant enum will also implement core::default::Default and its corresponding variant will be marked as #[default].
    • Conversions: The macro implements From<OriginalEnum> and From<&OriginalEnum> for the new discriminant enum, allowing you to easily convert your data into its discriminant form.
    • Trait Implementation: It implements the IntoDiscriminant trait (from strum) on your original enum, providing a .discriminant() method.
  3. Debug generated macro code

    master

    If you need to inspect the code generated by Strum macros, you can use the STRUM_DEBUG environment variable during compilation.

    • Set STRUM_DEBUG=1 to dump all generated code for every type.
    • Set STRUM_DEBUG=YourType to dump only the code generated for a specific type named YourType.
  4. Configure `EnumDiscriminants` via `#[strum_discriminants]`

    master

    You can control the generation of the discriminant enum using the #[strum_discriminants(...)] attribute on your main enum. This allows you to override default naming, visibility, and pass through specific attributes to the generated variants.

    Supported Configuration Options:

    • name = "...": Sets the name of the generated discriminant enum.
    • vis = "...": Sets the visibility of the generated enum (e.g., pub, pub(crate)).
    • #[strum_discriminants(attribute)]: You can use this to proxy specific attributes to the generated variants. The attribute inside the parentheses must be a group (e.g., #[strum_discriminants(#[cfg(feature = "foo")])]).
  5. Available Strum macros

    master

    Strum provides several procedural macros to augment enums with string and metadata capabilities:

    MacroDescription
    EnumStringConverts strings to enum variants based on their name.
    DisplayConverts enum variants to strings
    FromReprConvert from an integer to an enum.
    AsRefStrImplement AsRef<str> for the enum
    IntoStaticStrImplements From<MyEnum> for &'static str on an enum
    EnumIterCreates a new type that iterates over the variants of an enum.
    EnumPropertyAdd custom properties to enum variants.
    EnumMessageAdd a verbose message to an enum variant.
    EnumDiscriminantsGenerate a new type with only the discriminant names.
    EnumCountAdd a constant usize equal to the number of variants.
    VariantArrayAdds an associated VARIANTS constant which is an array of all enum discriminants
    VariantNamesAdds an associated VARIANTS constant which is an array of discriminant names
  6. Use the `EnumIs` derive macro to check enum variants

    master

    The EnumIs macro automatically generates boolean check methods for each variant of an enum. For a variant named MyVariant, the macro generates a method named is_my_variant(). These methods are const, inline, and marked with #[must_use]. They return true if the enum instance matches that specific variant, and false otherwise.

    Note: If a variant has its disabled property set (via Strum attributes), the corresponding is_* method will not be generated for that variant.

  7. Convert enum variants to `&str` with `AsRefStr`

    master

    The AsRefStr derive macro implements AsRef<str> for your enum. This allows you to get a string slice of the variant name (or a custom serialized name) without allocating a new String.

    Customization:

    • Prefix/Suffix: Use #[strum(prefix = "...")] or #[strum(suffix = "...")] on the enum to apply a string to all variants.
    • Custom Name: Use #[strum(serialize = "...")] on a specific variant to change its string representation.
    use std::convert::AsRef;
    use strum_macros::AsRefStr;
    
    #[derive(AsRefStr, Debug)]
    #[strum(prefix = "/")]
    enum ColorWithPrefix {
        #[strum(serialize = "redred")]
        Red,
        Green,
    }
    
    assert_eq!("/redred", ColorWithPrefix::Red.as_ref());
    assert_eq!("/Green", ColorWithPrefix::Green.as_ref());
  8. Implement `Display` with `Display` macro

    master

    The Display derive macro implements std::fmt::Display for your enum. It determines the string representation based on these rules:

    1. Use the to_string property if present (only one allowed per variant).
    2. Use the longest serialize property if no to_string is present.
    3. Use the variant name if no attributes are present.
    4. Prepend strum(prefix = "...") or append strum(suffix = "...") if defined on the enum.
    5. Supports string interpolation for variants with fields.
    use std::string::ToString;
    use strum_macros::Display;
    
    #[derive(Display, Debug)]
    enum Color {
        #[strum(serialize = "redred")]
        Red,
        Green,
        Yellow,
        #[strum(to_string = "purple with {sat} saturation")]
        Purple { sat: usize },
    }
    
    let purple = Color::Purple { sat: 10 };
    assert_eq!(String::from("purple with 10 saturation"), purple.to_string());
  9. Iterate over enum variants with `EnumIter`

    master

    The EnumIter derive macro implements strum::IntoEnumIterator for your enum. This allows you to iterate over all variants using YourEnum::iter().

    Note: For variants containing data, the iterator will use Default::default() to populate the fields. You cannot derive EnumIter on enums with lifetime bounds (e.g., MyEnum<'a>).

    use strum::IntoEnumIterator;
    use strum_macros::EnumIter;
    
    #[derive(EnumIter, Debug, PartialEq)]
    enum Color {
        Red,
        Green { range: usize },
        Blue(usize),
        Yellow,
    }
    
    for color in Color::iter() {
        println!("My favorite color is {:?}", color);
    }
  10. Check variant identity with `EnumIs`

    master

    The EnumIs derive macro generates helper methods for each variant to check if an enum instance matches that variant (e.g., my_enum.is_red()).

    use strum_macros::EnumIs;
    
    #[derive(EnumIs, Debug)]
    enum Color {
        Red,
        Green { range: usize },
    }
    
    let color = Color::Red;
    assert!(color.is_red());
  11. Convert enum to static string with `IntoStaticStr`

    master

    The IntoStaticStr derive macro implements From<YourEnum> and From<&'a YourEnum> for &'static str. This is useful for converting an enum variant into a static string slice, especially when the enum has lifetime bounds.

    use strum_macros::IntoStaticStr;
    
    #[derive(IntoStaticStr)]
    enum State<'a> {
        Initial(&'a str),
        Finished,
    }
    
    fn verify_state<'a>(s: &'a str) {
        let state = State::Initial(s);
        let right: &'static str = state.into();
        assert_eq!("Initial", right);
    }
  12. Attach metadata to variants with `EnumMessage`

    master

    The EnumMessage trait allows you to associate string messages, detailed messages, and documentation with enum variants. This is implemented by deriving EnumMessage and using the #[strum(message="...")] and #[strum(detailed_message="...")] attributes.

    Methods available:

    • get_message(): Returns the message assigned via message attribute.
    • get_detailed_message(): Returns the message assigned via detailed_message attribute.
    • get_documentation(): Returns the doc comment associated with the variant.
    • get_serializations(): Returns the list of serializations.
    # use std::fmt::Debug;
    // You need to bring the type into scope to use it!!!
    use strum::EnumMessage;
    
    #[derive(PartialEq, Eq, Debug, EnumMessage)]
    enum Pet {
        #[strum(message="I have a dog")]
        #[strum(detailed_message="My dog's name is Spots")]
        Dog,
        /// I am documented.
        #[strum(message="I don't have a cat")]
        Cat,
    }
    
    let my_pet = Pet::Dog;
    assert_eq!("I have a dog", my_pet.get_message().unwrap());