Skip to main content

allfeat_midds_v2_codegen/
lib.rs

1//! # MIDDS V2 Codegen - Procedural Macro for Dual-Mode Type Generation
2//!
3//! This crate provides the `runtime_midds` procedural macro that enables automatic
4//! transformation of Rust data structures between std and Substrate runtime modes.
5//!
6//! ## Overview
7//!
8//! The core functionality revolves around the `#[runtime_midds]` attribute macro that:
9//! - Generates two versions of each annotated type (std and runtime)
10//! - Automatically transforms `String` and `Vec<T>` fields to `BoundedVec` in runtime mode
11//! - Adds appropriate trait derivations for each compilation mode
12//! - Supports complex nested structures and enums
13//!
14//! ## Key Features
15//!
16//! ### Type Transformations
17//! - `String` → `BoundedVec<u8, ConstU32<N>>`
18//! - `Vec<T>` → `BoundedVec<T, ConstU32<N>>`
19//! - `Option<String>` → `Option<BoundedVec<u8, ConstU32<N>>>`
20//! - `Option<Vec<T>>` → `Option<BoundedVec<T, ConstU32<N>>>`
21//! - Recursive transformation for nested `Option` types
22//!
23//! ### Bound Specification
24//! Use `#[runtime_bound(N)]` attributes to specify maximum sizes:
25//! - On struct fields for field-level bounds
26//! - On enum variants for variant-level bounds (applies to all fields in that variant)
27//!
28//! ### Trait Derivations
29//! - **Runtime mode**: `Encode`, `Decode`, `DecodeWithMemTracking`, `TypeInfo`, `MaxEncodedLen`, `Debug`, `Clone`, `PartialEq`, `Eq`
30//! - **Std mode**: `Debug`, `Clone`, `PartialEq`, `Eq`
31//!
32//! ## Usage Examples
33//!
34//! ### Basic Struct
35//! ```rust
36//! use allfeat_midds_v2_codegen::runtime_midds;
37//!
38//! #[runtime_midds]
39//! pub struct MyStruct {
40//!     #[runtime_bound(256)]
41//!     pub title: String,
42//!
43//!     #[runtime_bound(64)]
44//!     pub tags: Vec<String>,
45//!
46//!     pub id: u64, // No transformation
47//! }
48//! ```
49//!
50//! ### Newtype Struct
51//! ```rust
52//! use allfeat_midds_v2_codegen::runtime_midds;
53//!
54//! #[runtime_midds]
55//! pub struct Identifier(#[runtime_bound(32)] String);
56//! ```
57//!
58//! ### Enum with Bounds
59//! ```rust
60//! use allfeat_midds_v2_codegen::runtime_midds;
61//!
62//! #[runtime_midds]
63//! pub enum WorkType {
64//!     Original,
65//!     #[runtime_bound(512)]
66//!     Medley(Vec<u64>),
67//!     #[runtime_bound(256)]
68//!     Adaptation(String, u32),
69//! }
70//! ```
71//!
72//! ### Optional Fields
73//! ```rust
74//! use allfeat_midds_v2_codegen::runtime_midds;
75//!
76//! #[runtime_midds]
77//! pub struct OptionalData {
78//!     #[runtime_bound(128)]
79//!     pub optional_title: Option<String>,
80//!
81//!     #[runtime_bound(32)]
82//!     pub optional_list: Option<Vec<u32>>,
83//! }
84//! ```
85//!
86//! ## Architecture
87//!
88//! The crate is organized into several modules:
89//! - [`attribute`] - Parsing and validation of `#[runtime_bound(N)]` attributes
90//! - [`transform`] - Type transformation logic between std and runtime modes
91//! - [`generate`] - Code generation utilities for structs and enums
92//! - [`error`] - Comprehensive error handling with detailed diagnostics
93
94#![deny(missing_docs)]
95#![deny(rustdoc::broken_intra_doc_links)]
96
97use proc_macro::TokenStream;
98use syn::{parse_macro_input, Data, DeriveInput};
99
100mod attribute;
101mod error;
102mod generate;
103mod transform;
104
105use attribute::AttributeParser;
106use enum_handler::EnumHandler;
107use error::{MacroError, MacroResult};
108use generate::GenerationConfig;
109use struct_handler::StructHandler;
110
111mod enum_handler;
112/// Sub-modules for handling different data structure types
113mod struct_handler;
114
115/// Attribute macro that transforms String and Vec<Type> fields to BoundedVec when runtime feature is enabled.
116///
117/// This is the core macro of the MIDDS V2 system, enabling dual-mode compilation of data structures
118/// for both std Rust applications and Substrate blockchain runtime environments.
119///
120/// # Syntax
121///
122/// Apply the macro to structs and enums:
123/// ```rust
124/// use allfeat_midds_v2_codegen::runtime_midds;
125///
126/// #[runtime_midds]
127/// pub struct MyType {
128///     #[runtime_bound(256)]  // Specify bound for transformable fields
129///     field: String,       // Will be transformed in runtime mode
130///     other: u32,          // No transformation needed
131/// }
132/// ```
133///
134/// # Supported Types
135///
136/// ## Structs
137/// - Named field structs: `struct S { field: Type }`
138/// - Tuple structs: `struct S(Type, Type)`
139/// - Unit structs: `struct S;`
140///
141/// ## Enums
142/// - Unit variants: `Variant`
143/// - Tuple variants: `Variant(Type, Type)`
144/// - Struct variants: `Variant { field: Type }`
145///
146/// # Bounds
147///
148/// Use `#[runtime_bound(N)]` to specify maximum sizes:
149///
150/// ## Field-Level Bounds (Structs)
151/// ```rust
152/// # use allfeat_midds_v2_codegen::runtime_midds;
153/// #[runtime_midds]
154/// struct Example {
155///     #[runtime_bound(256)]
156///     title: String,
157///     #[runtime_bound(64)]
158///     tags: Vec<String>,
159/// }
160/// ```
161///
162/// ## Variant-Level Bounds (Enums)
163/// ```rust
164/// # use allfeat_midds_v2_codegen::runtime_midds;
165/// #[runtime_midds]
166/// enum Example {
167///     Simple,
168///     #[runtime_bound(128)]
169///     WithData(String, Vec<u32>),
170/// }
171/// ```
172///
173/// # Transformations
174///
175/// | Original Type | Runtime Type |
176/// |---------------|--------------|
177/// | `String` | `BoundedVec<u8, ConstU32<N>>` |
178/// | `Vec<T>` | `BoundedVec<T, ConstU32<N>>` |
179/// | `Option<String>` | `Option<BoundedVec<u8, ConstU32<N>>>` |
180/// | `Option<Vec<T>>` | `Option<BoundedVec<T, ConstU32<N>>>` |
181/// | `&str` | `BoundedVec<u8, ConstU32<N>>` |
182///
183/// # Generated Traits
184///
185/// ## Runtime Mode (`#[cfg(feature = "runtime")]`)
186/// - `parity_scale_codec::Encode`
187/// - `parity_scale_codec::Decode`
188/// - `parity_scale_codec::DecodeWithMemTracking`
189/// - `scale_info::TypeInfo`
190/// - `parity_scale_codec::MaxEncodedLen`
191/// - `Debug`, `Clone`, `PartialEq`, `Eq`
192///
193/// ## Std Mode (`#[cfg(feature = "std")]`)
194/// - `Debug`, `Clone`, `PartialEq`, `Eq`
195///
196/// # Examples
197///
198/// ## Complete Example
199/// ```rust
200/// use allfeat_midds_v2_codegen::runtime_midds;
201///
202/// #[runtime_midds]
203/// pub struct MusicalWork {
204///     #[runtime_bound(256)]
205///     pub title: String,
206///
207///     #[runtime_bound(11)]
208///     pub iswc: Option<String>,
209///
210///     #[runtime_bound(128)]
211///     pub participants: Vec<u64>,
212///
213///     pub creation_year: Option<u16>,
214///     pub bpm: Option<u16>,
215/// }
216/// ```
217///
218/// This generates two versions:
219/// - Std: Uses `String`, `Vec<u64>`
220/// - Runtime: Uses `BoundedVec<u8, ConstU32<256>>`, `BoundedVec<u64, ConstU32<128>>`
221///
222/// ## Error Handling
223///
224/// The macro will emit compile errors for:
225/// - Missing `#[runtime_bound(N)]` on transformable fields
226/// - Invalid bound syntax
227/// - Unsupported type structures
228///
229/// # Implementation Notes
230///
231/// - Bounds are enforced at compile time in runtime mode
232/// - The macro preserves all existing attributes except `#[runtime_bound]`
233/// - Generic types are preserved and passed through unchanged
234/// - The transformation is purely syntactic - no runtime overhead
235#[proc_macro_attribute]
236pub fn runtime_midds(_args: TokenStream, input: TokenStream) -> TokenStream {
237    let input = parse_macro_input!(input as DeriveInput);
238
239    match process_derive_input(input) {
240        Ok(tokens) => tokens.into(),
241        Err(error) => error.into_compile_error().into(),
242    }
243}
244
245/// Main processing function for the derive input
246fn process_derive_input(input: DeriveInput) -> MacroResult<proc_macro2::TokenStream> {
247    // Create generation configuration
248    let config = GenerationConfig::new(
249        input.ident.clone(),
250        input.vis.clone(),
251        input.generics.clone(),
252        AttributeParser::filter_runtime_bound_attrs(&input.attrs)
253            .into_iter()
254            .cloned()
255            .collect(),
256    );
257
258    // Validate top-level attributes
259    AttributeParser::validate_attributes(&input.attrs)?;
260
261    // Process based on data structure type
262    match input.data {
263        Data::Struct(data_struct) => StructHandler::process_struct(&config, &data_struct),
264        Data::Enum(data_enum) => EnumHandler::process_enum(&config, &data_enum),
265        Data::Union(_) => Err(MacroError::unsupported_data_structure(
266            &input,
267            "union (only structs and enums are supported)",
268        )),
269    }
270}