Expand description

This crate contains a procedural macro attribute that can be placed on an impl block. It will generate an enum based on the functions defined in the impl block. The generated enum will have a variant for each function, and a new function map will be added to the impl block that will call the appropriate function based on the variant.

An example:

#[enum_from_functions]
impl Enum {
    fn foo() -> &'static str {
        "Foo"
    }
    fn bar() -> &'static str {
        "Bar"
    }

    fn baz() -> &'static str {
        "Baz"
    }
}

expands to:

enum Enum {
    Foo,
    Bar,
    Baz,
}

impl Enum {
    fn foo() -> &'static str {
        "Foo"
    }
    fn bar() -> &'static str {
        "Bar"
    }
    fn baz() -> &'static str {
        "Baz"
    }

    fn map(&self) -> &'static str {
        match self {
            Enum::Foo => Enum::foo(),
            Enum::Bar => Enum::bar(),
            Enum::Baz => Enum::baz(),
        }
    }
}

The signatures of all the functions in the impl block must be the same and must not use the self keyword. Aside from that, any function signature will work with this macro.

#[enum_from_functions]
impl Enum {
    // Causes a compile error because the `self` argument isn't allowed.
    fn foo(self) -> &'static str {
        "Foo"
    }
}
// Causes a compile error because the return types don't match.
#[enum_from_functions]
impl Enum {
    fn foo() -> &'static str {
        "Foo"
    }
    fn bar() -> String {
        "Bar".to_owned()
    }
}
// Causes a compile error because the argument types don't match.
#[enum_from_functions]
impl Enum {
    fn foo(_: i32) -> &'static str {
        "Foo"
    }
    fn bar(_: bool) -> &'static str {
        "Bar"
    }
}

async functions are allowed, but then all functions in the impl block must be async. The generated map function will also be async.

#[enum_from_functions]
impl Enum {
    async fn foo() -> &'static str {
        "Foo"
    }
    async fn bar() -> &'static str {
        "Bar"
    }
}

fn main() {
    async {
        assert_eq!(Enum::map(Enum::Foo).await, "Foo");
        assert_eq!(Enum::map(Enum::Bar).await, "Bar");
    }
}

You can also create an empty enum by not providing any functions in the impl block (though I’m not sure why you would want to do this).

#[enum_from_functions]
impl EmptyEnum {}

If you need to export the generated enum type out of its parent module, provide the pub argument to the macro attribute.

mod internal {
    #[enum_from_functions(pub)]
    impl Visible {
        fn example() -> bool {
            true
        }
    }
}

// Will compile because the generated `enum` is visible outside of the `internal` module.
use internal::Visible;
mod internal {
    #[enum_from_functions]
    impl NotVisible {
        fn example() -> bool {
            false
        }
    }
}

// Causes a compile error because the generated `enum` is not visible outside of the `internal` module.
use internal::NotVisible;

Items in the impl block that are not functions will be ignored and passed through to the output unchanged. Similarly, any attributes applied before or after the macro attribute will be applied to the generated enum declaration.

#[enum_from_functions]
#[derive(Debug)]
impl Enum {
    const FOO: &'static str = "Foo";
    fn foo() -> &'static str {
        Self::FOO
    }

    const BAR: &'static str = "Bar";
    fn bar() -> &'static str {
        Self::BAR
    }

    const BAZ: &'static str = "Baz";
    fn baz() -> &'static str {
        Self::BAZ
    }
}

Attribute Macros

  • A procedural macro attribute that generates an enum based on the functions defined in the impl block it annotates. See the crate documentation for more information.