nulid_macros/lib.rs
1//! Procedural macros for convenient NULID generation.
2//!
3//! This crate provides macros to simplify working with NULIDs in your code.
4//!
5//! # Examples
6//!
7//! ```ignore
8//! use nulid::nulid;
9//!
10//! // Generate a new NULID (panics on error)
11//! let id = nulid!();
12//!
13//! // Generate with explicit error handling
14//! let id = nulid!(?);
15//! ```
16
17use proc_macro::TokenStream;
18use quote::quote;
19
20/// Generates a new NULID at compile time.
21///
22/// This macro provides a convenient way to generate NULIDs without verbose error handling.
23///
24/// # Variants
25///
26/// - `nulid!()` - Generates a NULID, panicking on error (use in contexts where failure is acceptable)
27/// - `nulid!(?)` - Returns `Result<Nulid, Error>` for explicit error handling
28///
29/// # Examples
30///
31/// ```ignore
32/// use nulid::nulid;
33///
34/// // Simple generation (panics on error)
35/// let id = nulid!();
36/// println!("Generated ID: {}", id);
37///
38/// // With error handling
39/// fn create_id() -> nulid::Result<nulid::Nulid> {
40/// let id = nulid!(?)?;
41/// Ok(id)
42/// }
43///
44/// // In a function that can handle errors
45/// let id = nulid!(?).expect("Failed to generate NULID");
46/// ```
47///
48/// # Panics
49///
50/// The `nulid!()` variant (without `?`) will panic if NULID generation fails,
51/// which can happen if the system's random number generator is unavailable.
52///
53/// Use `nulid!(?)` if you need to handle errors gracefully.
54#[proc_macro]
55pub fn nulid(input: TokenStream) -> TokenStream {
56 // Check if "?" was passed as an argument for fallible mode
57 let fallible_mode = if input.is_empty() {
58 false
59 } else {
60 // Parse as a single token
61 let input_str = input.to_string();
62 let trimmed = input_str.trim();
63
64 if trimmed == "?" {
65 true
66 } else {
67 return syn::Error::new(
68 proc_macro2::Span::call_site(),
69 "expected `?` or no argument; usage: nulid!() or nulid!(?)",
70 )
71 .to_compile_error()
72 .into();
73 }
74 };
75
76 let expanded = if fallible_mode {
77 // Return Result for error handling
78 quote! {
79 ::nulid::Nulid::new()
80 }
81 } else {
82 // Panic on error for convenience
83 quote! {
84 ::nulid::Nulid::new().expect("Failed to generate NULID")
85 }
86 };
87
88 TokenStream::from(expanded)
89}