component_model_types/
component.rs

1/// Provides a generic interface for setting a component of a certain type on an object.
2///
3/// This trait abstracts the action of setting or replacing a component, where a component
4/// can be any part or attribute of an object, such as a field value. It is designed to be
5/// generic over the type of the component being set (`T`) and the type that can be converted
6/// into the component (`IntoT`). This design allows for flexible implementations that can
7/// accept various types that can then be converted into the required component type.
8///
9/// # Type Parameters
10///
11/// - `T`: The type of the component to be set on the implementing object. This type represents
12///   the final form of the component as it should be stored or represented in the object.
13/// - `IntoT`: The type that can be converted into `T`. This allows the `assign` method to accept
14///   different types that are capable of being transformed into the required component type `T`,
15///   providing greater flexibility in setting the component.
16///
17/// # Examples
18///
19/// Implementing `Assign` to set a name string on a struct:
20///
21/// ```rust
22/// use component_model_types::Assign; // use crate `component_model` instead of crate `component_model_types` unless you need to use crate `component_model_types` directly
23///
24/// struct MyStruct {
25///   name: String,
26/// }
27///
28/// impl< IntoT : Into< String > > Assign< String, IntoT > for MyStruct
29/// {
30///   fn assign( &mut self, component : IntoT )
31///   {
32///     self.name = component.into();
33///   }
34/// }
35///
36/// let mut obj = MyStruct { name : String::new() };
37/// obj.assign( "New Name" );
38/// assert_eq!( obj.name, "New Name" );
39/// ```
40#[ cfg( feature = "types_component_assign" ) ]
41pub trait Assign< T, IntoT >
42where
43  IntoT : Into< T >,
44{
45  /// Sets or replaces the component on the object with the given value.
46  ///
47  /// This method takes ownership of the given value (`component`), which is of type `IntoT`.
48  /// `component` is then converted into type `T` and set as the component of the object.
49  fn assign( &mut self, component : IntoT );
50
51  /// Sets or replaces the component on the object with the given value.
52  /// Unlike function (`assing`) function (`impute`) also consumes self and return it what is useful for builder pattern.
53  #[ inline( always ) ]
54  #[ must_use ]
55  fn impute( mut self, component : IntoT ) -> Self
56  where
57    Self : Sized,
58  {
59    self.assign( component );
60    self
61  }
62
63}
64
65/// Extension trait to provide a method for setting a component on an `Option<Self>`
66/// if the `Option` is currently `None`. If the `Option` is `Some`, the method will
67/// delegate to the `Assign` trait's `assign` method.
68///
69/// # Type Parameters
70///
71/// - `T`: The type of the component to be set on the implementing object. This type represents
72///   the final form of the component as it should be stored or represented in the object.
73///
74/// # Examples
75///
76/// Using `option_assign` to set a component on an `Option`:
77///
78/// ```rust
79/// use component_model_types::{ Assign, OptionExt }; // use crate `component_model` instead of crate `component_model_types` unless you need to use crate `component_model_types` directly
80///
81/// struct MyStruct
82/// {
83///   name : String,
84/// }
85///
86/// impl< IntoT : Into< MyStruct > > Assign< MyStruct, IntoT > for MyStruct
87/// {
88///   fn assign( &mut self, component : IntoT )
89///   {
90///     self.name = component.into().name;
91///   }
92/// }
93///
94/// let mut opt_struct: Option< MyStruct > = None;
95/// opt_struct.option_assign( MyStruct { name: "New Name".to_string() } );
96/// assert_eq!( opt_struct.unwrap().name, "New Name" );
97/// ```
98#[ cfg( feature = "types_component_assign" ) ]
99pub trait OptionExt< T > : sealed::Sealed
100where
101  T : Sized + Assign< T, T >,
102{
103  /// Sets the component on the `Option` if it is `None`.
104  ///
105  /// If the `Option` is `Some`, the `assign` method is called to update the existing value.
106  ///
107  /// # Parameters
108  ///
109  /// - `src`: The value to assign to the `Option`.
110  fn option_assign( & mut self, src : T );
111}
112
113#[ cfg( feature = "types_component_assign" ) ]
114impl< T > OptionExt< T > for Option< T >
115where
116  T : Sized + Assign< T, T >,
117{
118  #[ inline( always ) ]
119  fn option_assign( & mut self, src : T )
120  {
121    match self
122    {
123      Some( self_ref ) => Assign::assign( self_ref, Into::< T >::into( src ) ),
124      None => * self = Some( src ),
125    }
126  }
127}
128
129#[ cfg( feature = "types_component_assign" ) ]
130mod sealed
131{
132  pub trait Sealed {}
133  impl< T > Sealed for Option< T >
134  where
135    T : Sized + super::Assign< T, T >,
136  {}
137}
138
139/// The `AssignWithType` trait provides a mechanism to set a component on an object,
140/// utilizing the type information explicitly. This trait extends the functionality of `Assign`
141/// by allowing implementers to specify the component's type at the method call site,
142/// enhancing expressiveness in code that manipulates object states.
143///
144/// # Type Parameters
145///
146/// - `T`: The type of the component to be set on the implementing object. This specifies
147///   the exact type expected by the object as its component.
148/// - `IntoT`: A type that can be converted into `T`, providing flexibility in the types of values
149///   that can be used to set the component.
150///
151/// # Examples
152///
153/// Implementing `AssignWithType` to set a username on a struct:
154///
155/// ```rust
156/// use component_model_types::{ Assign, AssignWithType }; // use crate `component_model` instead of crate `component_model_types` unless you need to use crate `component_model_types` directly
157///
158/// struct UserProfile
159/// {
160///   username : String,
161/// }
162///
163/// impl< IntoT : Into< String > > Assign< String, IntoT > for UserProfile
164/// {
165///   fn assign( &mut self, component : IntoT )
166///   {
167///     self.username = component.into();
168///   }
169/// }
170///
171/// let mut user_profile = UserProfile { username : String::new() };
172/// user_profile.assign_with_type::< String, _ >("john_doe");
173///
174/// assert_eq!( user_profile.username, "john_doe" );
175/// ```
176#[ cfg( feature = "types_component_assign" ) ]
177pub trait AssignWithType
178{
179  /// Sets the value of a component by its type.
180  ///
181  /// This method allows an implementer of `AssignWithType` to set a component on `self`
182  /// where the component's type is `T`, and the input value is of type `IntoT`, which can be
183  /// converted into `T`. This method bridges the gap between dynamic type usage and static type
184  /// enforcement, providing a flexible yet type-safe interface for modifying object states.
185  ///
186  /// # Parameters
187  ///
188  /// - `component`: The value to assign to the component.
189  ///
190  /// # Type Parameters
191  ///
192  /// - `T`: The type of the component to be set on the implementing object.
193  /// - `IntoT`: A type that can be converted into `T`.
194  fn assign_with_type< T, IntoT >( & mut self, component : IntoT )
195  where
196    IntoT : Into< T >,
197    Self : Assign< T, IntoT >;
198}
199
200#[ cfg( feature = "types_component_assign" ) ]
201impl< S > AssignWithType for S
202{
203  #[ inline( always ) ]
204  fn assign_with_type< T, IntoT >( & mut self, component : IntoT )
205  where
206    IntoT : Into< T >,
207    Self : Assign< T, IntoT >,
208  {
209    Assign::< T, IntoT >::assign( self, component );
210  }
211}