Skip to main content

component_model_meta/
lib.rs

1#![doc(html_logo_url = "https://raw.githubusercontent.com/Wandalen/wTools/master/asset/img/logo_v3_trans_square.png")]
2#![doc(
3  html_favicon_url = "https://raw.githubusercontent.com/Wandalen/wTools/alpha/asset/img/logo_v3_trans_square_icon_small_v2.ico"
4)]
5#![doc(html_root_url = "https://docs.rs/component_model_derive_meta/latest/component_model_derive_meta/")]
6#![ cfg_attr( doc, doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/", "readme.md" ) ) ) ]
7#![ cfg_attr( not( doc ), doc = "Component model macro support" ) ]
8
9#[ allow( unused_imports ) ]
10use macro_tools::prelude::*;
11
12/// Popular type support for derive macro generation
13mod popular_types;
14
15#[ cfg( feature = "enabled" ) ]
16#[ cfg( any(
17  feature = "derive_components",
18  feature = "derive_component_from",
19  feature = "derive_from_components",
20  feature = "derive_component_assign",
21  feature = "derive_component_assign",
22  feature = "derive_components_assign"
23))]
24mod component
25{
26
27  //!
28  //! Implement couple of derives of general-purpose.
29  //!
30
31  #[ allow( unused_imports ) ]
32  use macro_tools::prelude::*;
33
34  #[ cfg( feature = "derive_component_assign" ) ]
35  pub mod component_assign;
36  #[ cfg( feature = "derive_component_from" ) ]
37  pub mod component_from;
38  #[ cfg(all(feature = "derive_component_assign", feature = "derive_components_assign")) ]
39  pub mod components_assign;
40  #[ cfg( feature = "derive_from_components" ) ]
41  pub mod from_components;
42  #[ cfg( feature = "derive_component_model" ) ]
43  pub mod component_model;
44}
45
46///
47/// Macro to implement `From` for each component (field) of a structure.
48/// This macro simplifies the creation of `From` trait implementations for struct fields,
49/// enabling easy conversion from a struct reference to its field types.
50///
51/// # Features
52///
53/// - Requires the `derive_component_from` feature to be enabled for use.
54/// - The `ComponentFrom` derive macro can be applied to structs to automatically generate
55///   `From` implementations for each field.
56///
57/// # Attributes
58///
59/// - `debug` : Optional attribute to enable debug-level output during the macro expansion process.
60///
61/// # Examples
62///
63/// Assuming the `derive_component_from` feature is enabled in your `Cargo.toml`, you can use the macro as follows :
64///
65/// ```rust
66/// # fn main()
67/// # {
68/// use component_model_meta ::ComponentFrom;
69///
70/// #[ derive( ComponentFrom ) ]
71/// struct Person
72/// {
73///   pub age: i32,
74///   pub name: String,
75/// }
76///
77/// let my_struct = Person { age: 10, name: "Hello".into() };
78/// let age: i32 = From ::from( &my_struct );
79/// let name: String = From ::from( &my_struct );
80/// dbg!( age );
81/// dbg!( name );
82/// // > age = 10
83/// // > name = "Hello"
84/// # }
85/// ```
86///
87#[ cfg( feature = "enabled" ) ]
88#[ cfg( feature = "derive_component_from" ) ]
89#[ proc_macro_derive(ComponentFrom, attributes(debug)) ]
90pub fn component_from(input: proc_macro::TokenStream) -> proc_macro::TokenStream 
91{
92  let result = component::component_from::component_from(input);
93  match result 
94  {
95  Ok(stream) => stream.into(),
96  Err(err) => err.to_compile_error().into(),
97 }
98}
99
100/// Derives the `Assign` trait for struct fields, allowing each field to be set
101/// with a value that can be converted into the field's type.
102///
103/// This macro facilitates the automatic implementation of the `Assign` trait for all
104/// fields within a struct, leveraging the power of Rust's type system to ensure type safety
105/// and conversion logic. It is particularly useful for builder patterns or mutating instances
106/// of data structures in a fluent and ergonomic manner.
107///
108/// # Attributes
109///
110/// - `debug` : An optional attribute to enable debugging of the trait derivation process.
111///
112/// # Conditions
113///
114/// - This macro is only enabled when the `derive_component_assign` feature is active in your `Cargo.toml`.
115///
116/// # Input Code Example
117///
118/// Given a struct definition annotated with `#[ derive( Assign ) ]` :
119///
120/// ```rust
121/// use component_model_types ::Assign;
122/// use component_model_meta ::Assign;
123///
124/// #[ derive( Default, PartialEq, Debug, Assign ) ]
125/// struct Person
126/// {
127///   age: i32,
128///   name: String,
129/// }
130///
131/// let mut person: Person = Default ::default();
132/// person.assign( 13 );
133/// person.assign( "John" );
134/// assert_eq!( person, Person { age: 13, name: "John".to_string() } );
135/// ```
136///
137/// # Generated Code Example
138///
139/// The procedural macro generates the following implementations for `Person` :
140///
141/// ```rust
142/// use component_model_types ::Assign;
143/// use component_model_meta ::Assign;
144///
145/// #[ derive( Default, PartialEq, Debug ) ]
146/// struct Person
147/// {
148///   age: i32,
149///   name: String,
150/// }
151///
152/// impl< IntoT > Assign< i32, IntoT > for Person
153/// where
154///   IntoT: Into< i32 >,
155/// {
156///   fn assign( &mut self, component: IntoT )
157///   {
158///     self.age = component.into();
159/// }
160/// }
161///
162/// impl< IntoT > Assign< String, IntoT > for Person
163/// where
164///   IntoT: Into< String >,
165/// {
166///   fn assign( &mut self, component: IntoT )
167///   {
168///     self.name = component.into();
169/// }
170/// }
171///
172/// let mut person: Person = Default ::default();
173/// person.assign( 13 );
174/// person.assign( "John" );
175/// assert_eq!( person, Person { age: 13, name: "John".to_string() } );
176/// ```
177/// This allows any type that can be converted into an `i32` or `String` to be set as
178/// the value of the `age` or `name` fields of `Person` instances, respectively.
179#[ cfg( feature = "enabled" ) ]
180#[ cfg( feature = "derive_component_assign" ) ]
181#[ proc_macro_derive(Assign, attributes(debug)) ]
182pub fn component_assign(input: proc_macro::TokenStream) -> proc_macro::TokenStream 
183{
184  let result = component::component_assign::component_assign(input);
185  match result 
186  {
187  Ok(stream) => stream.into(),
188  Err(err) => err.to_compile_error().into(),
189 }
190}
191
192///
193/// Derives the `ComponentsAssign` trait for a struct, enabling `components_assign` which set all fields at once.
194///
195/// This will work only if every field can be acquired from the passed value.
196/// In other words, the type passed as an argument to `components_assign` must implement `Into< T >` for each field type.
197///
198/// # Attributes
199///
200/// - `debug` : An optional attribute to enable debugging of the trait derivation process.
201///
202/// # Conditions
203///
204/// - This macro is only enabled when the `derive_components_assign` feature is active in your `Cargo.toml`.
205/// - The type must implement `Assign` (`derive( Assign )`)
206///
207/// # Limitations
208/// This trait cannot be derived, if the struct has fields with identical types
209///
210/// # Input Code Example
211///
212/// An example when we encapsulate parameters passed to a function in a struct.
213///
214/// ```rust, ignore
215/// use component_model :: { Assign, ComponentsAssign };
216///
217/// #[ derive( Default, Assign, ComponentsAssign ) ]
218/// struct BigOpts
219/// {
220///   cond: bool,
221///   int: i32,
222///   str: String,
223/// }
224///
225/// #[ derive( Default, Assign, ComponentsAssign ) ]
226/// struct SmallerOpts
227/// {
228///   cond: bool,
229///   int: i32,
230/// }
231///
232/// impl From< &BigOpts > for bool
233/// {
234///   fn from( value: &BigOpts ) -> Self
235///   {
236///     value.cond
237/// }
238/// }
239///
240/// impl From< &BigOpts > for i32
241/// {
242///   fn from( value: &BigOpts ) -> Self
243///   {
244///     value.int
245/// }
246/// }
247///
248/// fn take_big_opts( options: &BigOpts ) -> &String
249/// {
250///   &options.str
251/// }
252///
253/// fn take_smaller_opts( options: &SmallerOpts ) -> bool
254/// {
255///   !options.cond
256/// }
257///
258/// let options1 = BigOpts
259/// {
260///   cond: true,
261///   int: -14,
262///   ..Default ::default()
263/// };
264/// take_big_opts( &options1 );
265///
266/// let mut options2 = SmallerOpts ::default();
267/// options2.smaller_opts_assign( &options1 );
268/// take_smaller_opts( &options2 );
269/// ```
270///
271/// Which expands approximately into :
272///
273/// ```rust, ignore
274/// use component_model :: { Assign, ComponentsAssign };
275///
276/// #[ derive( Default ) ]
277/// struct BigOpts
278/// {
279///   cond: bool,
280///   int: i32,
281///   str: String,
282/// }
283///
284/// impl< IntoT > Assign< bool, IntoT > for BigOpts
285/// where
286///   IntoT: Into< bool >,
287/// {
288///   fn assign( &mut self, component: IntoT )
289///   {
290///     self.cond = component.into();
291/// }
292/// }
293///
294/// impl< IntoT > Assign< i32, IntoT > for BigOpts
295/// where
296///   IntoT: Into< i32 >,
297/// {
298///   fn assign( &mut self, component: IntoT )
299///   {
300///     self.int = component.into();
301/// }
302/// }
303///
304/// impl< IntoT > Assign< String, IntoT > for BigOpts
305/// where
306///   IntoT: Into< String >,
307/// {
308///   fn assign( &mut self, component: IntoT )
309///   {
310///     self.str = component.into();
311/// }
312/// }
313///
314/// pub trait BigOptsComponentsAssign< IntoT >
315/// where
316///   IntoT: Into< bool >,
317///   IntoT: Into< i32 >,
318///   IntoT: Into< String >,
319///   IntoT: Clone,
320/// {
321///   fn components_assign( &mut self, component: IntoT );
322/// }
323///
324/// impl< T, IntoT > BigOptsComponentsAssign< IntoT > for T
325/// where
326///   T: component_model ::Assign< bool, IntoT >,
327///   T: component_model ::Assign< i32, IntoT >,
328///   T: component_model ::Assign< String, IntoT >,
329///   IntoT: Into< bool >,
330///   IntoT: Into< i32 >,
331///   IntoT: Into< String >,
332///   IntoT: Clone,
333/// {
334///   fn components_assign( &mut self, component: IntoT )
335///   {
336///     component_model ::Assign :: < bool, _ > ::assign( self, component.clone() );
337///     component_model ::Assign :: < i32, _ > ::assign( self, component.clone() );
338///     component_model ::Assign :: < String, _ > ::assign( self, component.clone() );
339/// }
340/// }
341///
342/// #[ derive( Default ) ]
343/// struct SmallerOpts
344/// {
345///   cond: bool,
346///   int: i32,
347/// }
348///
349/// impl< IntoT > Assign< bool, IntoT > for SmallerOpts
350/// where
351///   IntoT: Into< bool >,
352/// {
353///   fn assign( &mut self, component: IntoT )
354///   {
355///     self.cond = component.into();
356/// }
357/// }
358///
359/// impl< IntoT > Assign< i32, IntoT > for SmallerOpts
360/// where
361///     IntoT: Into< i32 >,
362/// {
363///   fn assign( &mut self, component: IntoT )
364///   {
365///     self.int = component.into();
366/// }
367/// }
368///
369/// pub trait SmallerOptsComponentsAssign< IntoT >
370/// where
371///   IntoT: Into< bool >,
372///   IntoT: Into< i32 >,
373///   IntoT: Clone,
374/// {
375///   fn smaller_opts_assign( &mut self, component: IntoT );
376/// }
377///
378/// impl< T, IntoT > SmallerOptsComponentsAssign< IntoT > for T
379/// where
380///   T: component_model ::Assign< bool, IntoT >,
381///   T: component_model ::Assign< i32, IntoT >,
382///   IntoT: Into< bool >,
383///   IntoT: Into< i32 >,
384///   IntoT: Clone,
385/// {
386///   fn smaller_opts_assign( &mut self, component: IntoT )
387///   {
388///     component_model ::Assign :: < bool, _ > ::assign( self, component.clone() );
389///     component_model ::Assign :: < i32, _ > ::assign( self, component.clone() );
390/// }
391/// }
392///
393/// impl From< &BigOpts > for bool
394/// {
395///   fn from( value: &BigOpts ) -> Self
396///   {
397///     value.cond
398/// }
399/// }
400///
401/// impl From< &BigOpts > for i32
402/// {
403///   fn from( value: &BigOpts ) -> Self
404///   {
405///     value.int
406/// }
407/// }
408///
409/// fn take_big_opts( options: &BigOpts ) -> &String
410/// {
411///   &options.str
412/// }
413///
414/// fn take_smaller_opts( options: &SmallerOpts ) -> bool
415/// {
416///   !options.cond
417/// }
418///
419/// let options1 = BigOpts
420/// {
421///   cond: true,
422///   int: -14,
423///   ..Default ::default()
424/// };
425/// take_big_opts( &options1 );
426/// let mut options2 = SmallerOpts ::default();
427/// options2.smaller_opts_assign( &options1 );
428/// take_smaller_opts( &options2 );
429/// ```
430///
431#[ cfg( feature = "enabled" ) ]
432#[ cfg(all(feature = "derive_component_assign", feature = "derive_components_assign")) ]
433#[ proc_macro_derive(ComponentsAssign, attributes(debug)) ]
434pub fn components_assign(input: proc_macro::TokenStream) -> proc_macro::TokenStream 
435{
436  let result = component::components_assign::components_assign(input);
437  match result 
438  {
439  Ok(stream) => stream.into(),
440  Err(err) => err.to_compile_error().into(),
441 }
442}
443
444/// A procedural macro to automatically derive the `From< T >` trait implementation for a struct,
445/// enabling instances of one type to be converted from instances of another type.
446///
447/// It is part of type-based forming approach which requires each field having an unique type. Each field
448/// of the target struct must be capable of being individually converted from the source type `T`.
449/// This macro simplifies the implementation of type conversions, particularly useful for
450/// constructing a struct from another type with compatible fields. The source type `T` must
451/// implement `Into< FieldType >` for each field type of the target struct.
452///
453/// # Attributes
454///
455/// - `debug` : Optional. Enables debug printing during macro expansion.
456///
457/// # Requirements
458///
459/// - Available only when the feature flags `enabled` and `derive_from_components`
460///   are activated in your Cargo.toml. It's activated by default.
461///
462/// # Examples
463///
464/// Given the structs `Options1` and `Options2`, where `Options2` is a subset of `Options1` :
465///
466/// ```rust
467/// use component_model_meta ::FromComponents;
468///
469/// #[ derive( Debug, Default, PartialEq ) ]
470/// pub struct Options1
471/// {
472///   field1: i32,
473///   field2: String,
474///   field3: f32,
475/// }
476///
477/// impl From< &Options1 > for i32
478/// {
479///   #[ inline( always ) ]
480///   fn from( src: &Options1 ) -> Self
481///   {
482///     src.field1.clone()
483/// }
484/// }
485///
486/// impl From< &Options1 > for String
487/// {
488///   #[ inline( always ) ]
489///   fn from( src: &Options1 ) -> Self
490///   {
491///     src.field2.clone()
492/// }
493/// }
494///
495/// impl From< &Options1 > for f32
496/// {
497///   #[ inline( always ) ]
498///   fn from( src: &Options1 ) -> Self
499///   {
500///     src.field3.clone()
501/// }
502/// }
503///
504/// #[ derive( Debug, Default, PartialEq, FromComponents ) ]
505/// pub struct Options2
506/// {
507///   field1: i32,
508///   field2: String,
509/// }
510///
511/// let o1 = Options1 { field1: 42, field2: "Hello, world!".to_string(), field3: 13.01 };
512///
513/// // Demonstrating conversion from Options1 to Options2
514/// let o2: Options2 = Into :: < Options2 > ::into( &o1 );
515/// let expected = Options2 { field1: 42, field2: "Hello, world!".to_string() };
516/// assert_eq!( o2, expected );
517///
518/// // Alternative way using `.into()`
519/// let o2: Options2 = ( &o1 ).into();
520/// assert_eq!( o2, expected );
521///
522/// // Alternative way using `.from()`
523/// let o2 = Options2 ::from( &o1 );
524/// assert_eq!( o2, expected );
525/// ```
526///
527/// This demonstrates how `Options2` can be derived from `Options1` using the `FromComponents` macro,
528/// automatically generating the necessary `From< &Options1 >` implementation for `Options2`, facilitating
529/// an easy conversion between these types based on their compatible fields.
530///
531#[ cfg( feature = "enabled" ) ]
532#[ cfg( feature = "derive_from_components" ) ]
533#[ proc_macro_derive(FromComponents, attributes(debug)) ]
534pub fn from_components(input: proc_macro::TokenStream) -> proc_macro::TokenStream 
535{
536  let result = component::from_components::from_components(input);
537  match result 
538  {
539  Ok(stream) => stream.into(),
540  Err(err) => err.to_compile_error().into(),
541 }
542}
543
544/// Unified derive macro that combines all component model functionality into a single annotation.
545/// 
546/// The `ComponentModel` derive automatically generates implementations for :
547/// - `Assign` : Basic component assignment with type-safe field setting
548/// - `ComponentsAssign` : Multiple component assignment from tuples (when applicable) 
549/// - `ComponentFrom` : Create objects from single components (when applicable)
550/// - `FromComponents` : Create objects from multiple components (when applicable)
551/// 
552/// This eliminates the need to apply multiple individual derives and reduces boilerplate.
553/// 
554/// # Features
555/// 
556/// - Requires the `derive_component_model` feature to be enabled for use.
557/// - Automatically detects which trait implementations are appropriate for the struct.
558/// - Handles type conflicts gracefully by skipping conflicting implementations.
559/// 
560/// # Attributes
561///
562/// - `debug` : Optional attribute to enable debug-level output during macro expansion.
563/// - `component` : Optional field-level attribute for customizing component behavior.
564///
565/// # Limitations
566///
567/// `ComponentModel` only supports structs with named fields. It does not support:
568///
569/// - Tuple structs: `struct Point(i32, i32);` will produce a compilation error
570/// - Unit structs: `struct Unit;` will produce a compilation error
571/// - Enums and unions
572///
573/// For tuple structs, use the individual derives `ComponentFrom` and `Assign` instead:
574///
575/// ```rust
576/// use component_model_meta:: { ComponentFrom, Assign as AssignDerive };
577/// use component_model_types::Assign;
578///
579/// #[ derive( Default, ComponentFrom, AssignDerive ) ]
580/// struct Point( i32, i32 );
581/// ```
582///
583/// # Examples
584/// 
585/// ```rust
586/// use component_model_meta ::ComponentModel;
587/// use component_model_types ::Assign;
588/// 
589/// #[ derive( Default, ComponentModel ) ]
590/// struct Config
591/// {
592///   host: String,
593///   port: i32,
594///   enabled: bool,
595/// }
596/// 
597/// let mut config = Config ::default();
598/// 
599/// // Use Assign trait (auto-generated)
600/// config.assign( "localhost".to_string() );
601/// config.assign( 8080i32 );
602/// config.enabled_set( true ); // Use field-specific method to avoid type ambiguity
603/// 
604/// // Use fluent builder pattern (auto-generated)
605/// let config2 = Config ::default()
606///   .impute( "api.example.com".to_string() )
607///   .impute( 3000i32 )
608///   .enabled_with( false ); // Use field-specific method to avoid type ambiguity
609/// ```
610#[ cfg( feature = "enabled" ) ]
611#[ cfg( feature = "derive_component_model" ) ]
612#[ proc_macro_derive(ComponentModel, attributes(debug, component)) ]
613pub fn component_model(input: proc_macro::TokenStream) -> proc_macro::TokenStream
614{
615  let result = component::component_model::component_model(input);
616  match result
617  {
618  Ok(stream) => stream.into(),
619  Err(err) => err.to_compile_error().into(),
620 }
621}