Overview
This crate provides a derive macro called Tagged and a tag attribute for enums so that data can be associated with each variant. The derive macro will automatically generate methods to access the associated tag data. This allows us to avoid writing long match functions.
Getting started
Install the crate using cargo:
Or by updating your Cargo.toml:
[]
= "0.1.0"
Derive the Tagged macro for your enum, and associate data with the tag attribute:
use Tagged;
Access the associated data using the generated functions:
#
#
#
Detailed usage
In a tag declaration, the first value must be a plain identifier without quotations. This is the tag name, and it's required. Everything that comes after the name is executed as an expression. Expressions must be relatively simple mathematical expressions or bare values.
Examples
# use Tagged;
#
#
# use Tagged;
#
#
# use Tagged;
#
#
# use enumrs::Tagged;
# #[derive(Tagged)]
# pub enum MyEnum {
// WRONG: can't evaluate because 'String' is not in scope at compile time.
#[tag( name, String::from("Name") )]
Variant4,
# }
# use enumrs::Tagged;
# #[derive(Tagged)]
# pub enum MyEnum {
// WRONG: can't evaluate because 'my_custom_func' is not in scope at compile time.
#[tag( name, my_custom_func() )]
Variant5,
# }
# use enumrs::Tagged;
# #[derive(Tagged)]
# pub enum MyEnum {
// WRONG: no other attribute with name 'other_attribute' defined.
#[tag( name, other_attribute + 3 )]
Variant6,
# }
Types
The result of the expression must be one of the following simple types, and will be returned from functions as the associated rust value type, wrapped in an Option. Any variants that don't have a particular attribute will return None.
| Simple type | Rust type | Return type |
|---|---|---|
| Float | f64 | Option<f64> |
| Integer | i32 | Option<i32> |
| String | &'static str | Option<&'static str> |
| Boolean | bool | Option<bool> |
Operators
The expressions in the tag attributes can use any of the operators available from the evalexpr crate. The only caveat is that the context for the expression will be empty at evaluation time except for other attributes on the same enum variant.
So this works:
# use Tagged;
#
#
But this does not:
# use enumrs::Tagged;
pub const VALUE: i32 = 3;
#[derive(Tagged)]
pub enum MyEnum {
#[tag( id, VALUE + 1 )]
Variant1,
// ...
}
Contributing
Anyone is welcome to contribute. It's a small crate, so your contributions are likely to have a large impact on the future of this library. I'll review and discuss any pull requests, but there may be a bit of a delay. Don't hesitate to ping me over and over for a review until I respond.
Future
Overview
The future development of this crate should tend toward simplicity and robustness. If possible, there should be only a few attributes to remember, and using those attributes should be a simple and intuitive process. This might not always be possible, as there are likely going to be edge cases (like providing names for generated functions) that require additional attributes, but simple and robust is the goal.
Features
Add configuration attributes
Currently, Tagged generates a function for each tag name, and this might not always be what we want. There should be a way to specify particular function names to use for different attributes, something like:
# use enumrs::Tagged;
#[derive(Tagged)]
#[map(id,get_id)]
pub enum MyEnum {
#[tag(id, 0)]
Variant1,
#[tag(id, 1)]
Variant2
}
Should generate something like:
Handle more complex expressions
In some of the examples above, you see that things like function calls are not supported. I'd like to change this by providing some way to escape the compile-time evaluation of the expression and insert it directly into the generated code. This would allow us to reference functions in the tags and call those functions at runtime.
This code:
pub fn myfunc() -> i32 {
0
}
#[derive(Tagged)]
pub enum MyEnum {
#[tag( id, myfunc() + 1 )]
Variant1,
// no tag on this one
Variant2
// ...
}
Should generate something like:
# use Tagged;
Improve code quality
Right now, testing is a little barebones, and I'd like to spend some time writing some unit tests to check edge cases and particular types of failures. I'm also relatively new to proc-macro crates, and I need to find someone to give me a code review.
Improve error reporting
If an expression couldn't be evaluated, two tags have different evaluated data types, or some other failure occurs, I'd like better output at compile time to make debugging easier. Currently, compilation will panic with a simple error message, but there isn't a lot of detail.