derive_atom_set/lib.rs
1#![deny(warnings)]
2use proc_macro::TokenStream;
3use syn::{DeriveInput, parse_macro_input};
4
5mod atom_set;
6
7/// Derives an efficient `AtomSet` implementation for interned CSS identifiers.
8///
9/// This proc macro automatically generates optimized string-to-enum matching code.
10///
11/// ## Variant Attributes
12///
13/// - `#[default]`: Marks this variant as the empty/fallback value (returns empty string)
14/// - `#[atom("custom")]`: Overrides the default string representation
15///
16/// ## Naming Convention
17///
18/// If `#[atom("")]` is not provided a string is derived from the variant name:
19/// - `Px` → `"px"`
20/// - `FontSize` → `"font-size"`
21/// - `WebkitTransform` → `"webkit-transform"`
22///
23/// # Example
24///
25/// ```rust
26/// // Provide this trait definition:
27/// trait AtomSet {
28/// fn from_str(keyword: &str) -> Self;
29/// fn to_str(self) -> &'static str;
30/// fn len(&self) -> u32;
31/// fn from_bits(bits: u32) -> Self;
32/// fn as_bits(&self) -> u32;
33/// }
34/// use derive_atom_set::AtomSet;
35///
36/// #[derive(Debug, Default, Copy, Clone, PartialEq, AtomSet)]
37/// pub enum MyAtomSet {
38/// #[default]
39/// Unknown, // Must provide an empty default!
40///
41/// // Absolute units
42/// Px, Pt, Pc, In, Cm, Mm, Q,
43///
44/// // Relative units
45/// Em, Ex, Ch, Rem, Lh,
46///
47/// // Viewport units
48/// Vw, Vh, Vi, Vb, Vmin, Vmax,
49///
50/// // Container query units
51/// Cqw, Cqh, Cqi, Cqb, Cqmin, Cqmax,
52///
53/// // Special case
54/// #[atom("%")]
55/// Percent,
56/// }
57///
58/// // Usage:
59/// assert_eq!(MyAtomSet::from_str("px"), MyAtomSet::Px);
60/// assert_eq!(MyAtomSet::from_str("PX"), MyAtomSet::Px); // Case insensitive matches
61/// assert_eq!(MyAtomSet::Px.to_str(), "px");
62/// assert_eq!(MyAtomSet::Percent.to_str(), "%");
63/// assert_eq!(MyAtomSet::from_str("unknown"), MyAtomSet::Unknown);
64/// ```
65#[proc_macro_derive(AtomSet, attributes(default, atom))]
66pub fn derive_atom_set(input: TokenStream) -> TokenStream {
67 let ast = parse_macro_input!(input as DeriveInput);
68 atom_set::generate(proc_macro2::TokenStream::new(), ast).into()
69}