EnPow
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.
Usage 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.
Using just enpow
use enpow::enpow;
#[enpow(Var, VarAsRef)]
#[enpow_derive(Debug, PartialEq)]
#[derive(Clone, Debug, PartialEq)]
pub enum Token<Span> {
Plus(
Span
),
Number {
span: Span,
value: u64,
}
}
assert_eq!(Token::Plus(3).plus(), Some(3));
assert_eq!(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.number_as_mut().unwrap().span = 20;
assert_eq!(num.number(), Some(TokenNumber { span: 20, value: 7 }))
#[derive(Clone, Debug, PartialEq)]
pub enum Token<Span> {
Plus(
Span
),
Number {
span: Span,
value: u64,
}
}
#[allow(unused)]
#[derive(Debug, PartialEq)]
pub struct TokenNumber<Span> {
pub span: Span,
pub value: u64,
}
#[allow(unused)]
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct TokenNumberRef<'token_number, Span> {
pub span: &'token_number Span,
pub value: &'token_number u64,
}
#[allow(unused)]
#[derive(Debug, PartialEq)]
pub struct TokenNumberMut<'token_number, Span> {
pub span: &'token_number mut Span,
pub value: &'token_number mut u64,
}
#[automatically_derived]
#[allow(unused)]
impl<Span> Token<Span> {
pub fn plus(self) -> Option<Span> {
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,
}
}
}
assert_eq!(Token::Plus(3).plus(), Some(3));
assert_eq!(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.number_as_mut().unwrap().span = 20;
assert_eq!(num.number(), Some(TokenNumber { span: 20, value: 7 }))
Using just extract
use enpow::extract;
#[extract(All)]
#[extract_derive(Clone, Debug, PartialEq)]
#[derive(Clone, Debug, PartialEq)]
pub enum Token<Span> {
Plus(
Span
),
Number {
span: Span,
value: u64,
}
}
assert_eq!(TokenPlus((2,3)), TokenPlus((2,3)));
assert_eq!(
TokenNumber { span: (0, 4), value: 1024 },
TokenNumber { span: (0, 4), value: 1024 }
);
#[derive(Clone, Debug, PartialEq)]
pub enum Token<Span> {
Plus(TokenPlus<Span>),
Number(TokenNumber<Span>),
}
#[derive(Clone, Debug, PartialEq)]
pub struct TokenPlus<Span>(
pub Span
);
#[derive(Clone, Debug, PartialEq)]
pub struct TokenNumber<Span> {
pub span: Span,
pub value: u64,
}
assert_eq!(TokenPlus((2,3)), TokenPlus((2,3)));
assert_eq!(
TokenNumber { span: (0, 4), value: 1024 },
TokenNumber { span: (0, 4), value: 1024 }
);
Combining extract
and enpow
use enpow::{enpow, extract};
#[extract(Named)]
#[extract_derive(Clone, Debug, PartialEq)]
#[enpow(IsVar)]
#[derive(Clone, Debug, PartialEq)]
pub enum Token<Span> {
Plus(
Span
),
Number {
span: Span,
value: u64,
}
}
let token = Token::Number(TokenNumber { span: (0, 3), value: 1024 });
assert!(token.is_number_and(|num: &TokenNumber<_>| num.value == 1024));
#[derive(Clone, Debug, PartialEq)]
pub enum Token<Span> {
Plus(
Span
),
Number(TokenNumber<Span>),
}
#[automatically_derived]
#[allow(unused)]
impl<Span> Token<Span> {
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,
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct TokenNumber<Span> {
pub span: Span,
pub value: u64,
}
let token = Token::Number(TokenNumber { span: (0, 3), value: 1024 });
assert!(token.is_number_and(|num: &TokenNumber<_>| num.value == 1024));
Inspiration
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.
Contribution
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.
License
© 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