4 releases (2 breaking)
0.3.0 | Aug 14, 2023 |
---|---|
0.2.0 | Jul 25, 2023 |
0.1.1 | Jul 25, 2023 |
0.1.0 | Jul 25, 2023 |
0.0.0 |
|
#1728 in Procedural macros
30 downloads per month
17KB
240 lines
enum-from-functions.rs
A procedural macro that will create an enum with associated functions that each have a corresponding variant.
Documentation can be found inline or on docs.rs.
lib.rs
:
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 {
async fn foo() -> &'static str {
"Foo"
}
unsafe fn bar(baz: i32) -> &'static str {
"Bar"
}
}
expands to:
enum Enum {
Foo,
Bar {
baz: i32
},
}
impl Enum {
async fn foo() -> &'static str {
"Foo"
}
unsafe fn bar(baz: i32) -> &'static str {
"Bar"
}
async unsafe fn map(&self) -> &'static str {
match self {
Enum::Foo => Enum::foo().await,
Enum::Bar(baz) => Enum::bar(baz),
}
}
}
The signatures of functions in the impl
block may be different, so long as they all have the same return type.
Note that fn f() -> T
and async fn f() -> T
are considered to return the same type, even though the latter
technically returns a impl Future<Output = T>
. See
the async
keyword documentation for more information.
#[enum_from_functions]
impl Enum {
fn foo(baz: i32) -> &'static str {
"Foo"
}
async fn bar(&self, baz: bool) -> &'static str {
"Bar"
}
}
// 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()
}
}
async
, const
and unsafe
functions are supported. The presence of any of these keywords will result in the
generated map
function having the same keyword. For this reason, async
and const
functions cannot be present in
the same impl
block (though unsafe
functions can be present with either of the other two).
#[enum_from_functions]
impl Enum {
async fn foo() -> &'static str {
"Foo"
}
const fn bar() -> &'static str {
"Bar"
}
// This would result in `async const map(...` which is not supported in Rust.
}
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
}
}
Dependencies
~0.9–1.4MB
~27K SLoC