penum/lib.rs
1#![doc = include_str!("../README.md")]
2
3use proc_macro::TokenStream;
4
5mod dispatch;
6mod error;
7mod factory;
8mod penum;
9mod services;
10mod utils;
11
12/// Use this to make an enum conform to a pattern with or without trait
13/// bounds.
14///
15/// # Examples
16/// It's also possible to make an enum conform to multiple shapes by
17/// seperating a `shape` with `|` symbol, for example:
18/// ```rust
19/// #[penum( (T) | (T, T) | { num: T } where T: Copy )]
20/// enum Foo {
21/// Bar(i32),
22/// Ber(u32, i32),
23/// Bur { num: f32 }
24/// }
25/// ```
26///
27/// Also, If an enum should break a `pattern`, like if a variant doesn't
28/// implement the correct `Trait`, an error would occur:
29/// ```rust
30/// #[penum( (T) | (T, T) | { num: T } where T: Copy )]
31/// enum Foo {
32/// Bar(String),
33/// ^^^^^^
34/// // ERROR: `String` doesn't implement `Copy`
35/// Ber(u32, i32),
36/// Bur { num: f32 }
37/// }
38/// ```
39/// ..or if a variant doesn't match the specified `shape`:
40/// ```rust
41/// #[penum( (T) | (T, T) | { num: T } where T: Copy )]
42/// enum Foo {
43/// Bar(u32),
44/// Ber(u32, i32, i32),
45/// ^^^^^^^^^^^^^
46/// // Found: `Ber(u32, i32, i32)`
47/// // Expected: `(T) | (T, T) | { num: T }`
48/// Bur { num: f32 }
49/// }
50/// ```
51/// Sometime we don't care about specifying a `where clause` and just
52/// want our enum to follow a specific `shape`. This is done by
53/// specifing `_`:
54/// ```rust
55/// #[penum( (_) | (_, _) | { num: _ } )]
56/// enum Foo {
57/// Bar(u32),
58/// Ber(u32, i32, i32),
59/// Bur { num: f32 }
60/// }
61/// ```
62/// If your not into generics, use `impl` expressions instead:
63/// ```rust
64/// #[penum( (impl Copy, ..) | { num: f32 }]
65/// enum Foo {
66/// Bar(u32),
67/// Ber(u32, i32, i32),
68/// Bur { num: f32 }
69/// }
70/// ```
71#[proc_macro_attribute]
72pub fn penum(attr: TokenStream, input: TokenStream) -> TokenStream {
73 services::penum_expand(attr, input)
74}
75
76/// Use this to express how `ToString` should be implemented through variants descriminant.
77///
78/// # Example
79///
80/// ```rust
81/// #[penum::to_string]
82/// enum EnumVariants {
83/// Variant0 = "Return on match",
84/// Variant1(i32) = "Return {f0} on match",
85/// Variant2(i32, u32) = stringify!(f0, f1).to_string(),
86/// Variant3 { name: String } = format!("My string {name}"),
87/// Variant4 { age: u32 } = age.to_string(),
88/// }
89/// let enum_variants = Enum::Variant0;
90/// println!("{}", enum_variants.to_string());
91/// ```
92#[proc_macro_attribute]
93pub fn to_string(_: TokenStream, input: TokenStream) -> TokenStream {
94 services::to_string_expand(input)
95}
96
97/// Use this to express how `Display` should be implemented through variants descriminant.
98///
99/// # Example
100///
101/// ```rust
102/// #[penum::fmt]
103/// enum EnumVariants {
104/// Variant0 = "Return on match",
105/// Variant1(i32) = "Return {f0} on match",
106/// Variant2(i32, u32) = stringify!(f0, f1).to_string().fmt(f),
107/// Variant3 { name: String } = format!("My string {name}").fmt(f),
108/// Variant4 { age: u32 } = write!(f, age.to_string()),
109/// }
110/// let enum_variants = Enum::Variant0;
111/// println!("{}", enum_variants);
112/// ```
113#[proc_macro_attribute]
114pub fn fmt(_: TokenStream, input: TokenStream) -> TokenStream {
115 services::fmt_expand(input)
116}
117
118/// Use this to express how `Into<T>` should be implemented through variants descriminant.
119///
120/// # Example
121///
122/// ```rust
123/// #[penum::into(String)]
124/// enum EnumVariants {
125/// Variant0 = "Return on match".into(),
126/// Variant1(i32) = format!("Return {f0} on match"),
127/// Variant2(i32, u32) = stringify!(f0, f1).to_string(),
128/// Variant3 { name: String } = format!("My string {name}"),
129/// Variant4 { age: u32 } = age.to_string(),
130/// }
131/// let enum_variants = Enum::Variant0;
132/// println!("{}", enum_variants.into());
133/// ```
134#[proc_macro_attribute]
135pub fn into(attr: TokenStream, input: TokenStream) -> TokenStream {
136 services::into_expand(attr, input)
137}
138
139/// Use this to express how `Deref<Target = T>` should be implemented through variants descriminant.
140///
141/// # Example
142///
143/// ```rust
144/// #[penum::deref(str)]
145/// enum EnumVariants {
146/// Variant0 = "Return on match",
147/// Variant1 = { "Evaluated" },
148/// Variant2 = concat!(i32, hello),
149/// Variant3(&'static str) = f0,
150/// Variant4 = &EnumVariants::Variant0,
151/// }
152/// let enum_variants = Enum::Variant0;
153/// println!("{}", &*enum_variants);
154/// ```
155#[proc_macro_attribute]
156pub fn deref(attr: TokenStream, input: TokenStream) -> TokenStream {
157 services::deref_expand(attr, input, None)
158}
159
160/// Use this to express that you want the enum to implement `deref() -> &str`, `as_str()` and `as_ref()`;
161///
162/// # Example
163///
164/// ```rust
165/// #[penum::static_str]
166/// enum EnumVariants {
167/// Variant0 = "Return on match",
168/// Variant1 = { "Evaluated" },
169/// Variant2 = concat!(i32, hello),
170/// Variant3(&'static str) = { f0 },
171/// Variant4 = &EnumVariants::Variant0,
172/// }
173/// let enum_variants = Enum::Variant0;
174/// assert_eq!("Return on match", &enum_variants);
175/// assert_eq!("Return on match", enum_variants.as_str());
176/// assert_eq!("Return on match", enum_variants.as_ref());
177/// ```
178#[proc_macro_attribute]
179pub fn static_str(_: TokenStream, input: TokenStream) -> TokenStream {
180 services::static_str(input)
181}
182
183/// Use this when you want to be able to associate a ...
184/// UNDER DEVELOPMENT
185/// # Example
186///
187/// ```rust
188/// #[penum::lazy_string]
189/// enum EnumVariants {
190/// Variant0 = "Return on match",
191/// Variant1(i32) = "{f0}"
192/// }
193/// let enum_variants = Enum::Variant1(10);
194/// assert_eq!("Return on match", &enum_variants);
195/// assert_eq!("Return on match", enum_variants.as_str());
196/// assert_eq!("Return on match", enum_variants.as_ref());
197/// ```
198// #[proc_macro_attribute]
199#[allow(unused)]
200fn lazy_string(_: TokenStream, input: TokenStream) -> TokenStream {
201 services::lazy_string(input)
202}