EnPow is a procedural macro crate used to enPower user defined Enums with many methods usually known from the standard library's Result<T, E>
and Option<T>
. It can generate methods like fn is_<variant>(&self) -> bool
or fn unwrap_<variant>(self) -> <inner>
, supporting variants with named or unnamed fields (or none), as well as generics. See the enpow
macro documentation for details on the specific methods supported.
Additionally, this crate allows to extract the data associated with each enum variant into separate structs, allowing for more compact code e.g. when designing an Abstract Syntax Tree. See the extract
macro documentation for more details.
It is also possible to combine both macros when keeping them in the right order: first extract
and then enpow
. Combining both macros avoids generating separate structs for Ref
or Mut
struct variants as demonstrated in one of the following examples.
The following examples demonstrate the separate usage of the macros enpow
and extract
, as well as their combined usage. See the macro's documentation for more details.
enpow
```rust use enpow::enpow;
pub enum Token {
/// +
Plus(
/// Source span
Span
),
/// Unsigned integer literal
Number {
/// Source span
span: Span,
/// Value
value: u64,
}
}
// Use the auto implementations asserteq!(Token::Plus(3).plus(), Some(3)); asserteq!(Token::Plus(7).number(), None); assert_eq!(Token::Number { span: 0, value: 42 }.number().unwrap().span, 0);
let mut num = Token::Number { span: 10, value: 7 }; *num.numberasmut().unwrap().span = 20; assert_eq!(num.number(), Some(TokenNumber { span: 20, value: 7 })) ```
See generated code
```rust
pub enum Token {
/// +
Plus(
/// Source span
Span
),
/// Unsigned integer literal
Number {
/// Source span
span: Span,
/// Value
value: u64,
}
}
/// Unsigned integer literal pub struct TokenNumber { /// Source span pub span: Span, /// Value pub value: u64, }
/// Unsigned integer literal pub struct TokenNumberRef<'tokennumber, Span> { /// Source span pub span: &'tokennumber Span, /// Value pub value: &'token_number u64, }
/// Unsigned integer literal pub struct TokenNumberMut<'tokennumber, Span> { /// Source span pub span: &'tokennumber mut Span, /// Value pub value: &'token_number mut u64, }
impl Token { pub fn plus(self) -> Option { match self { Token::Plus(f0) => Some(f0), _ => None, } }
pub fn plus_as_ref(&self) -> Option<&Span> {
match self {
Token::Plus(f0) => Some(f0),
_ => None,
}
}
pub fn plus_as_mut(&mut self) -> Option<&mut Span> {
match self {
Token::Plus(f0) => Some(f0),
_ => None,
}
}
pub fn number(self) -> Option<TokenNumber<Span>> {
match self {
Token::Number { span, value } => Some(TokenNumber { span, value }),
_ => None,
}
}
pub fn number_as_ref(&self) -> Option<TokenNumberRef<Span>> {
match self {
Token::Number { span, value } => Some(TokenNumberRef { span, value }),
_ => None,
}
}
pub fn number_as_mut(&mut self) -> Option<TokenNumberMut<Span>> {
match self {
Token::Number { span, value } => Some(TokenNumberMut { span, value }),
_ => None,
}
}
}
// Use the auto implementations asserteq!(Token::Plus(3).plus(), Some(3)); asserteq!(Token::Plus(7).number(), None); assert_eq!(Token::Number { span: 0, value: 42 }.number().unwrap().span, 0);
let mut num = Token::Number { span: 10, value: 7 }; *num.numberasmut().unwrap().span = 20; assert_eq!(num.number(), Some(TokenNumber { span: 20, value: 7 })) ```
extract
```rust use enpow::extract;
pub enum Token {
/// +
Plus(
/// Source span
Span
),
/// Unsigned integer literal
Number {
/// Source span
span: Span,
/// Value
value: u64,
}
}
// Use Debug and PartialEq asserteq!(TokenPlus((2,3)), TokenPlus((2,3))); asserteq!( TokenNumber { span: (0, 4), value: 1024 }, TokenNumber { span: (0, 4), value: 1024 } ); ```
See generated code
```rust
pub enum Token {
/// +
Plus(TokenPlus),
/// Unsigned integer literal
Number(TokenNumber),
}
/// +
pub struct TokenPlus(
/// Source span
pub Span
);
/// Unsigned integer literal pub struct TokenNumber { /// Source span pub span: Span, /// Value pub value: u64, }
// Use Debug and PartialEq asserteq!(TokenPlus((2,3)), TokenPlus((2,3))); asserteq!( TokenNumber { span: (0, 4), value: 1024 }, TokenNumber { span: (0, 4), value: 1024 } ); ```
extract
and enpow
```rust use enpow::{enpow, extract};
pub enum Token {
/// +
Plus(
/// Source span
Span
),
/// Unsigned integer literal
Number {
/// Source span
span: Span,
/// Value
value: u64,
}
}
// Use the auto implementations let token = Token::Number(TokenNumber { span: (0, 3), value: 1024 }); assert!(token.isnumberand(|num: &TokenNumber<_>| num.value == 1024)); ```
See generated code
```rust
pub enum Token {
/// +
Plus(
/// Source span
Span
),
/// Unsigned integer literal
Number(TokenNumber),
}
impl Token { pub fn is_plus(&self) -> bool { match self { Token::Plus(f0) => true, _ => false, } }
pub fn is_plus_and(&self, f: impl FnOnce(&Span) -> bool) -> bool {
match self {
Token::Plus(f0) => f(f0),
_ => false,
}
}
pub fn is_number(&self) -> bool {
match self {
Token::Number(f0) => true,
_ => false,
}
}
pub fn is_number_and(&self, f: impl FnOnce(&TokenNumber<Span>) -> bool) -> bool {
match self {
Token::Number(f0) => f(f0),
_ => false,
}
}
}
/// Unsigned integer literal pub struct TokenNumber { /// Source span pub span: Span, /// Value pub value: u64, }
// Use the auto implementations let token = Token::Number(TokenNumber { span: (0, 3), value: 1024 }); assert!(token.isnumberand(|num: &TokenNumber<_>| num.value == 1024)); ```
While the first plan for this crate was limited to simple unwrap_as
methods and alike, the crate variantly
was a great inspiration to take this idea way further. It can be seen as limited alternative to this crate.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as below, without any additional terms or conditions.
© 2022 Florian Köhler.
This project is licensed at your option under either of
The SPDX license identifier for this project is MIT OR Apache-2.0
.
Licensing derived from arnavyc/dual-licensed-mit-apache