1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/// Provides a generic interface for setting a component of a certain type on an object.
///
/// This trait abstracts the action of setting or replacing a component, where a component
/// can be any part or attribute of an object, such as a field value. It is designed to be
/// generic over the type of the component being set ( `T` ) and the type that can be converted
/// into the component ( `IntoT` ). This design allows for flexible implementations that can
/// accept various types that can then be converted into the required component type.
///
/// # Type Parameters
///
/// - `T` : The type of the component to be set on the implementing object. This type represents
///   the final form of the component as it should be stored or represented in the object.
/// - `IntoT` : The type that can be converted into `T`. This allows the `set` method to accept
///   different types that are capable of being transformed into the required component type `T`,
///   providing greater flexibility in setting the component.
///
/// # Examples
///
/// Implementing `ComponentAssign` to set a name string on a struct :
///
/// ```rust
/// use former::ComponentAssign;
///
/// struct MyStruct
/// {
///   name : String,
/// }
///
/// impl< IntoT : Into< String > > ComponentAssign< String, IntoT > for MyStruct
/// {
///   fn assign( &mut self, component : IntoT )
///   {
///     self.name = component.into();
///   }
/// }
///
/// let mut obj = MyStruct { name : String::new() };
/// obj.assign( "New Name" );
/// assert_eq!( obj.name, "New Name" );
/// ```
#[ cfg( any( feature = "derive_component_assign", feature = "derive_components_assign" ) ) ]
pub trait ComponentAssign< T, IntoT >
where
  IntoT : Into< T >,
{
  /// Sets or replaces the component on the object with the given value.
  ///
  /// This method takes ownership of the given value ( `component` ), which is of type `IntoT`.
  /// `component` is then converted into type `T` and set as the component of the object.
  fn assign( &mut self, component : IntoT );
}

/// The `AssignWithType` trait provides a mechanism to set a component on an object, utilizing the type information explicitly. This trait extends the functionality of `SetComponen`t by allowing implementers to specify the component's type at the method call site, enhancing expressiveness in code that manipulates object states.
///
/// ### Method Detail
///
/// - `assign_with_type::< T, IntoT >( &mut self, component : IntoT )`
///
/// This method allows an implementer of `SetWithTyp`e to set a component on self where the component's type is T, and the input value is of type `IntoT`, which can be converted into `T`. This method bridges the gap between dynamic type usage and static type enforcement, providing a flexible yet type-safe interface for modifying object states.
///
/// ### Type Parameters
///
/// - `T` : The type of the component to be set on the implementing object. This specifies the exact type expected by the object as its component.
/// - `IntoT` : A type that can be converted into T, providing flexibility in the types of values that can be used to set the component.
///
/// ### Example
///
/// ```rust
/// use former::{ ComponentAssign, AssignWithType };
///
/// struct UserProfile
/// {
///   username : String,
/// }
///
/// impl< IntoT : Into< String > > ComponentAssign< String, IntoT > for UserProfile
//  where String: From< String >,
/// {
///   fn assign( &mut self, component : IntoT )
///   {
///     self.username = component.into();
///   }
/// }
///
/// let mut user_profile = UserProfile { username : String::new() };
/// user_profile.assign_with_type::< String, _ >( "john_doe" );
///
/// assert_eq!( user_profile.username, "john_doe" );
/// ```
///

#[ cfg( any( feature = "derive_component_assign", feature = "derive_components_assign" ) ) ]
pub trait AssignWithType
{
  /// Function to set value of a component by its type.
  fn assign_with_type< T, IntoT >( &mut self, component : IntoT )
  where
    IntoT : Into< T >,
    Self : ComponentAssign< T, IntoT >;
}

#[ cfg( any( feature = "derive_component_assign", feature = "derive_components_assign" ) ) ]
impl< S > AssignWithType for S
{

  #[ inline( always ) ]
  fn assign_with_type< T, IntoT >( &mut self, component : IntoT )
  where
    IntoT : Into< T >,
    Self : ComponentAssign< T, IntoT >,
  {
    ComponentAssign::< T, IntoT >::assign( self, component );
  }

}