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}