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}