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 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
/// 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 `assign` 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 `Assign` to set a name string on a struct:
///
/// ```rust
/// use former_types::Assign; // use crate `former` instead of crate `former_types` unless you need to use crate `former_types` directly
///
/// struct MyStruct {
///   name: String,
/// }
///
/// impl< IntoT : Into< String > > Assign< 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 = "types_component_assign" ) ) ]
pub trait Assign< 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 );
}
/// Extension trait to provide a method for setting a component on an `Option<Self>`
/// if the `Option` is currently `None`. If the `Option` is `Some`, the method will
/// delegate to the `Assign` trait's `assign` method.
///
/// # 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.
///
/// # Examples
///
/// Using `option_assign` to set a component on an `Option`:
///
/// ```rust
/// use former_types::{ Assign, OptionExt }; // use crate `former` instead of crate `former_types` unless you need to use crate `former_types` directly
///
/// struct MyStruct
/// {
///   name : String,
/// }
///
/// impl< IntoT : Into< MyStruct > > Assign< MyStruct, IntoT > for MyStruct
/// {
///   fn assign( &mut self, component : IntoT )
///   {
///     self.name = component.into().name;
///   }
/// }
///
/// let mut opt_struct: Option< MyStruct > = None;
/// opt_struct.option_assign( MyStruct { name: "New Name".to_string() } );
/// assert_eq!( opt_struct.unwrap().name, "New Name" );
/// ```
#[ cfg( any( feature = "types_component_assign" ) ) ]
pub trait OptionExt< T > : sealed::Sealed
where
  T : Sized + Assign< T, T >,
{
  /// Sets the component on the `Option` if it is `None`.
  ///
  /// If the `Option` is `Some`, the `assign` method is called to update the existing value.
  ///
  /// # Parameters
  ///
  /// - `src`: The value to assign to the `Option`.
  fn option_assign( & mut self, src : T );
}
#[ cfg( any( feature = "types_component_assign" ) ) ]
impl< T > OptionExt< T > for Option< T >
where
  T : Sized + Assign< T, T >,
{
  #[ inline( always ) ]
  fn option_assign( & mut self, src : T )
  {
    match self
    {
      Some( self_ref ) => Assign::assign( self_ref, Into::< T >::into( src ) ),
      None => * self = Some( src ),
    }
  }
}
#[ cfg( any( feature = "types_component_assign" ) ) ]
mod sealed
{
  pub trait Sealed {}
  impl< T > Sealed for Option< T >
  where
    T : Sized + super::Assign< T, T >,
  {}
}
/// The `AssignWithType` trait provides a mechanism to set a component on an object,
/// utilizing the type information explicitly. This trait extends the functionality of `Assign`
/// by allowing implementers to specify the component's type at the method call site,
/// enhancing expressiveness in code that manipulates 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.
///
/// # Examples
///
/// Implementing `AssignWithType` to set a username on a struct:
///
/// ```rust
/// use former_types::{ Assign, AssignWithType }; // use crate `former` instead of crate `former_types` unless you need to use crate `former_types` directly
///
/// struct UserProfile
/// {
///   username : String,
/// }
///
/// impl< IntoT : Into< String > > Assign< String, IntoT > for UserProfile
/// {
///   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 = "types_component_assign" ) ) ]
pub trait AssignWithType
{
  /// Sets the value of a component by its type.
  ///
  /// This method allows an implementer of `AssignWithType` 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.
  ///
  /// # Parameters
  ///
  /// - `component`: The value to assign to the component.
  ///
  /// # Type Parameters
  ///
  /// - `T`: The type of the component to be set on the implementing object.
  /// - `IntoT`: A type that can be converted into `T`.
  fn assign_with_type< T, IntoT >( & mut self, component : IntoT )
  where
    IntoT : Into< T >,
    Self : Assign< T, IntoT >;
}
#[ cfg( any( feature = "types_component_assign" ) ) ]
impl< S > AssignWithType for S
{
  #[ inline( always ) ]
  fn assign_with_type< T, IntoT >( & mut self, component : IntoT )
  where
    IntoT : Into< T >,
    Self : Assign< T, IntoT >,
  {
    Assign::< T, IntoT >::assign( self, component );
  }
}