Skip to main content

tnuctipun_derive/
lib.rs

1use proc_macro::TokenStream;
2
3mod field_witnesses;
4mod mongo_comparable;
5
6/// Procedural macro to generate field witnesses for a struct.
7///
8/// This macro automatically generates:
9/// - Struct marker types for each field (always in PascalCase following Rust conventions)
10/// - FieldName implementations for each field marker (returns MongoDB field names)
11/// - HasField implementations to access field values with type safety
12///
13/// Note: The generated field witnesses are scoped within a module named `<struct_name>_fields`
14/// at the same module level as the derived struct. This prevents naming conflicts when multiple
15/// structs have fields with the same names, even across different modules.
16///
17/// # Important: Naming Behavior
18///
19/// The field naming strategy only affects MongoDB field names returned by `FieldName::field_name()`.
20/// Struct marker names are always converted to PascalCase regardless of the naming strategy.
21///
22/// # Attributes
23///
24/// ## Container-level attributes
25///
26/// - `#[tnuctipun(field_naming = "strategy")]` - Apply a naming strategy to MongoDB field names only
27///   - Built-in strategies: "PascalCase", "camelCase"
28/// - `#[tnuctipun(include_private = true)]` - Include private fields in witness generation
29///   - If not specified or set to false, private fields are skipped
30///   - When true, both public and private fields generate witnesses
31///
32/// ## Field-level attributes
33///
34/// - `#[tnuctipun(rename = "name")]` - Override the MongoDB field name for this specific field
35/// - `#[tnuctipun(skip)]` - Skip generating witnesses for this field
36///
37/// # Examples
38///
39/// ## Basic usage (default behavior):
40///
41/// ```ignore
42/// use tnuctipun::derive::FieldWitnesses;
43///
44/// #[derive(FieldWitnesses)]
45/// struct User {
46///     user_name: String,
47///     email_address: String,
48/// }
49///
50/// // Generated struct markers (always PascalCase):
51/// // - user_fields::UserName
52/// // - user_fields::EmailAddress
53///
54/// // MongoDB field names (kept as-is by default):
55/// // - UserName::field_name() returns "user_name"
56/// // - EmailAddress::field_name() returns "email_address"
57/// ```
58///
59/// ## With field naming strategy:
60///
61/// ```ignore
62/// #[derive(FieldWitnesses)]
63/// #[tnuctipun(field_naming = "camelCase")]
64/// struct User {
65///     user_name: String,
66///     email_address: String,
67/// }
68///
69/// // Generated struct markers (unchanged - always PascalCase):
70/// // - user_fields::UserName
71/// // - user_fields::EmailAddress
72///
73/// // MongoDB field names (transformed by strategy):
74/// // - UserName::field_name() returns "userName"
75/// // - EmailAddress::field_name() returns "emailAddress"
76/// ```
77///
78/// With field-level overrides:
79///
80/// ```ignore
81/// #[derive(FieldWitnesses)]
82/// #[tnuctipun(field_naming = "camelCase")]
83/// struct User {
84///     user_name: String,              // -> "userName"
85///     #[tnuctipun(rename = "email")]
86///     email_address: String,          // -> "email" (override)
87///     #[tnuctipun(skip)]
88///     internal_id: String,            // Skipped entirely
89/// }
90/// ```
91///
92/// With private field inclusion:
93///
94/// ```ignore
95/// #[derive(FieldWitnesses)]
96/// #[tnuctipun(include_private = true)]
97/// struct User {
98///     pub user_name: String,          // Public field - included
99///     email_address: String,          // Private field - included due to include_private = true
100/// }
101///
102/// #[derive(FieldWitnesses)]
103/// struct UserWithoutPrivate {
104///     pub user_name: String,          // Public field - included
105///     email_address: String,          // Private field - skipped (include_private defaults to false)
106/// }
107/// ```
108///
109/// Multiple structs with same field names don't conflict:
110///
111/// ```ignore
112/// mod admin {
113///     #[derive(FieldWitnesses)]
114///     struct User {
115///         name: String,
116///         permissions: Vec<String>,
117///     }
118///     // Generates: admin::user_fields::Name (different from the above)
119/// }
120/// ```
121///
122/// The macro generates a module containing field witness types for type-safe field access.
123/// For a struct named `User`, the generated module will be `user_fields` containing
124/// field witness types for each field in the struct.
125#[proc_macro_derive(FieldWitnesses, attributes(tnuctipun))]
126pub fn derive_field_witnesses(input: TokenStream) -> TokenStream {
127    field_witnesses::derive_field_witnesses(input)
128}
129
130/// Procedural macro to generate MongoComparable implementations for a struct.
131///
132/// This macro automatically generates implementations of the MongoComparable trait
133/// for each field in the struct, enabling MongoDB query operations.
134///
135/// Note: This macro requires FieldWitnesses to also be derived on the same struct
136/// to generate the necessary field markers and trait implementations.
137///
138/// ## Attributes
139///
140/// The MongoComparable derive macro supports the same container-level attributes as FieldWitnesses:
141///
142/// - `#[tnuctipun(include_private = true)]`
143/// - Include private fields in trait implementations
144/// - If not specified or set to false, private fields are skipped
145/// - When true, both public and private fields generate MongoComparable implementations
146///
147/// Example:
148///
149/// ```ignore
150/// use tnuctipun::derive::{FieldWitnesses, MongoComparable};
151///
152/// #[derive(FieldWitnesses, MongoComparable)]
153/// struct User {
154///     name: String,
155///     age: i32,
156///     tags: Vec<String>
157/// }
158///
159/// // The macro generates MongoComparable implementations like:
160/// // impl MongoComparable<String, String> for User {}
161/// // impl MongoComparable<i32, i32> for User {}  
162/// // impl MongoComparable<Vec<String>, String> for User {}
163/// // And many other compatible type combinations...
164/// ```
165///
166/// With private field inclusion:
167///
168/// ```ignore
169/// #[derive(FieldWitnesses, MongoComparable)]
170/// #[tnuctipun(include_private = true)]
171/// struct User {
172///     pub name: String,    // Public field - included
173///     private_id: u64,     // Private field - included due to include_private = true
174/// }
175/// ```
176///
177/// The macro generates trait implementations that enable type-safe MongoDB operations
178/// by providing evidence that specific field types can be compared with specific value types.
179#[proc_macro_derive(MongoComparable)]
180pub fn derive_mongo_comparable(input: TokenStream) -> TokenStream {
181    mongo_comparable::derive_mongo_comparable(input)
182}