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 >
42{
43 /// Sets or replaces the component on the object with the given value.
44 ///
45 /// This method takes ownership of the given value (`component`), which is of type `IntoT`.
46 /// For standard implementations, `component` is converted into type `T` using `Into< T >`.
47 /// For popular types, custom conversion logic may be used.
48 fn assign(&mut self, component: IntoT);
49
50 /// Sets or replaces the component on the object with the given value.
51 /// Unlike function (`assing`) function (`impute`) also consumes self and return it what is useful for builder pattern.
52 #[ inline( always ) ]
53 #[ must_use ]
54 fn impute(mut self, component: IntoT) -> Self
55 where
56 Self: Sized,
57 {
58 self.assign(component);
59 self
60 }
61}
62
63/// Extension trait to provide a method for setting a component on an `Option< Self >`
64/// if the `Option` is currently `None`. If the `Option` is `Some`, the method will
65/// delegate to the `Assign` trait's `assign` method.
66///
67/// # Type Parameters
68///
69/// - `T` : The type of the component to be set on the implementing object. This type represents
70/// the final form of the component as it should be stored or represented in the object.
71///
72/// # Examples
73///
74/// Using `option_assign` to set a component on an `Option` :
75///
76/// ```rust
77/// 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
78///
79/// struct MyStruct
80/// {
81/// name: String,
82/// }
83///
84/// impl< IntoT: Into< MyStruct > > Assign< MyStruct, IntoT > for MyStruct
85/// {
86/// fn assign( &mut self, component: IntoT )
87/// {
88/// self.name = component.into().name;
89/// }
90/// }
91///
92/// let mut opt_struct: Option< MyStruct > = None;
93/// opt_struct.option_assign( MyStruct { name: "New Name".to_string() } );
94/// assert_eq!( opt_struct.unwrap().name, "New Name" );
95/// ```
96#[ cfg( feature = "types_component_assign" ) ]
97pub trait OptionExt< T > : sealed ::Sealed
98where
99 T: Sized + Assign< T, T >,
100{
101 /// Sets the component on the `Option` if it is `None`.
102 ///
103 /// If the `Option` is `Some`, the `assign` method is called to update the existing value.
104 ///
105 /// # Parameters
106 ///
107 /// - `src` : The value to assign to the `Option`.
108 fn option_assign(&mut self, src: T);
109}
110
111#[ cfg( feature = "types_component_assign" ) ]
112impl< T > OptionExt< T > for Option< T >
113where
114 T: Sized + Assign< T, T >,
115{
116 #[ inline( always ) ]
117 fn option_assign(&mut self, src: T)
118 {
119 match self
120 {
121 Some(self_ref) => Assign ::assign(self_ref, Into :: < T > ::into(src)),
122 None => *self = Some(src),
123 }
124 }
125}
126
127#[ cfg( feature = "types_component_assign" ) ]
128mod sealed
129{
130 pub trait Sealed {}
131 impl< T > Sealed for Option< T > where T: Sized + super ::Assign< T, T > {}
132}
133
134/// The `AssignWithType` trait provides a mechanism to set a component on an object,
135/// utilizing the type information explicitly. This trait extends the functionality of `Assign`
136/// by allowing implementers to specify the component's type at the method call site,
137/// enhancing expressiveness in code that manipulates object states.
138///
139/// # Type Parameters
140///
141/// - `T` : The type of the component to be set on the implementing object. This specifies
142/// the exact type expected by the object as its component.
143/// - `IntoT` : A type that can be converted into `T`, providing flexibility in the types of values
144/// that can be used to set the component.
145///
146/// # Examples
147///
148/// Implementing `AssignWithType` to set a username on a struct :
149///
150/// ```rust
151/// 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
152///
153/// struct UserProfile
154/// {
155/// username: String,
156/// }
157///
158/// impl< IntoT: Into< String > > Assign< String, IntoT > for UserProfile
159/// {
160/// fn assign( &mut self, component: IntoT )
161/// {
162/// self.username = component.into();
163/// }
164/// }
165///
166/// let mut user_profile = UserProfile { username: String ::new() };
167/// user_profile.assign_with_type :: < String, _ >("john_doe");
168///
169/// assert_eq!( user_profile.username, "john_doe" );
170/// ```
171#[ cfg( feature = "types_component_assign" ) ]
172pub trait AssignWithType
173{
174 /// Sets the value of a component by its type.
175 ///
176 /// This method allows an implementer of `AssignWithType` to set a component on `self`
177 /// where the component's type is `T`, and the input value is of type `IntoT`, which can be
178 /// converted into `T`. This method bridges the gap between dynamic type usage and static type
179 /// enforcement, providing a flexible yet type-safe interface for modifying object states.
180 ///
181 /// # Parameters
182 ///
183 /// - `component` : The value to assign to the component.
184 ///
185 /// # Type Parameters
186 ///
187 /// - `T` : The type of the component to be set on the implementing object.
188 /// - `IntoT` : A type that can be converted into `T`.
189 fn assign_with_type< T, IntoT >(&mut self, component: IntoT)
190 where
191 IntoT: Into< T >,
192 Self: Assign< T, IntoT >;
193}
194
195#[ cfg( feature = "types_component_assign" ) ]
196impl< S > AssignWithType for S
197{
198 #[ inline( always ) ]
199 fn assign_with_type< T, IntoT >(&mut self, component: IntoT)
200 where
201 IntoT: Into< T >,
202 Self: Assign< T, IntoT >,
203 {
204 Assign :: < T, IntoT > ::assign(self, component);
205 }
206}