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 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
/// `PseudoDefault` trait allows to create a cheap default instance of a type, which **does not claim to be useful**.
///
/// The difference of `PseudoDefault` from `Default` is the relaxed expectation of the created instance to be useful.
///
/// The main use case of the trait is when we need to create a cheap instance of a type without any arguments, only to throw away afterwards. Therefore, created instance does not need to be a decent one.
///
/// This trait allows to avoid unsafe code in certain use cases. For instance:
/// * We can avoid tricks such as uninit, manually-drop, etc. that requires to be extremely careful, when we could've actually created a valid instance much more easily.
/// * We can use pseudo-default to fill the gaps when we need to take out an element from a collection of types that cannot implement Default.
///
/// Note that pseudo-default requirement is more relaxed than that of default, and hence,
/// * types implementing Default can implement PseudoDefault,
/// * additionally, types that cannot implement Default can manually implement PseudoDefault, provided that it is safe and cheap to create a pseudo instance of the type without any arguments.
///
/// # Example
///
/// Consider the following fictional type `Share` which divides a whole into pieces. Without providing the `number_of_shares`, this type does not have a meaning.
///
/// **Therefore, we cannot justify implementing `Default`, it would be misleading.**
///
/// If we still need to be able to create Share's for some reason, we can simply use `pseudo_default`. We would know that the created type does not promise to make sense behaviorally; however, it is still a cheap and valid instance that can be safely dropped.
///
/// ```rust
/// use orx_pseudo_default::PseudoDefault;
///
/// struct Share {
/// number_of_shares: std::num::NonZeroUsize,
/// }
///
/// impl Share {
/// fn share_size(&self, whole_amount: usize) -> usize {
/// whole_amount / self.number_of_shares
/// }
/// }
///
/// impl PseudoDefault for Share {
/// fn pseudo_default() -> Self {
/// Self {
/// number_of_shares: std::num::NonZeroUsize::new(1).unwrap(),
/// }
/// }
/// }
/// ```
///
/// A more advanced use case could be the following. Assume that we are trying to create a vec wrapper called `TakeVec` with the following features;
/// * it allows to take out elements by index by a method called `take`
/// * we should be able to wrap an allocated vec without any additional allocation
/// * we need to be able to give back the originally allocated vec
/// * we want to achieve this without unsafe code
///
/// It is trivial to implement this with `Default` but we want to be less restrictive on the constraint so that it works for non-default types as well. We can use PseudoDefault for this.
///
/// ```rust
/// use orx_pseudo_default::PseudoDefault;
/// # struct Share {
/// # number_of_shares: std::num::NonZeroUsize,
/// # }
/// #
/// # impl Share {
/// # fn share_size(&self, whole_amount: usize) -> usize {
/// # whole_amount / self.number_of_shares
/// # }
/// # }
/// #
/// # impl PseudoDefault for Share {
/// # fn pseudo_default() -> Self {
/// # Self {
/// # number_of_shares: std::num::NonZeroUsize::new(1).unwrap(),
/// # }
/// # }
/// # }
/// struct TakeVec<T>(Vec<T>);
///
/// impl<T> From<Vec<T>> for TakeVec<T> {
/// fn from(inner: Vec<T>) -> Self {
/// Self(inner)
/// }
/// }
///
/// impl<T> From<TakeVec<T>> for Vec<T> {
/// fn from(value: TakeVec<T>) -> Self {
/// value.0
/// }
/// }
///
/// impl<T: PseudoDefault> TakeVec<T> {
/// fn take(&mut self, index: usize) -> Option<T> {
/// self.0.get_mut(index).map(|element| {
/// let mut value = T::pseudo_default();
/// std::mem::swap(&mut value, element);
/// value
/// })
/// }
/// }
///
/// // implemented default types
///
/// let mut vec: TakeVec<_> = vec![0, 1, 2, 3].into();
/// assert_eq!(vec.take(2), Some(2));
///
/// let mut vec: TakeVec<_> = vec![0.to_string(), 1.to_string()].into();
/// assert_eq!(vec.take(0), Some(String::from("0")));
///
/// // non-default types
///
/// let mut vec: TakeVec<_> = vec![
/// Share {
/// number_of_shares: std::num::NonZeroUsize::new(42).unwrap(),
/// },
/// Share {
/// number_of_shares: std::num::NonZeroUsize::new(7).unwrap(),
/// },
/// ]
/// .into();
/// assert_eq!(vec.take(0).map(|x| x.number_of_shares.into()), Some(42));
/// ```
pub trait PseudoDefault {
/// `PseudoDefault` trait allows to create a cheap default instance of a type, which **does not claim to be useful**.
///
/// The difference of `PseudoDefault` from `Default` is the relaxed expectation of the created instance to be useful.
///
/// The main use case of the trait is when we need to create a cheap instance of a type without any arguments, only to throw away afterwards. Therefore, created instance does not need to be a decent one.
///
/// This trait allows to avoid unsafe code in certain use cases. For instance:
/// * We can avoid tricks such as uninit, manually-drop, etc. that requires to be extremely careful, when we could've actually created a valid instance much more easily.
/// * We can use pseudo-default to fill the gaps when we need to take out an element from a collection of types that cannot implement Default.
///
/// Note that pseudo-default requirement is more relaxed than that of default, and hence,
/// * types implementing Default can implement PseudoDefault,
/// * additionally, types that cannot implement Default can manually implement PseudoDefault, provided that it is safe and cheap to create a pseudo instance of the type without any arguments.
///
/// # Example
///
/// Consider the following fictional type `Share` which divides a whole into pieces. Without providing the `number_of_shares`, this type does not have a meaning.
///
/// **Therefore, we cannot justify implementing `Default`, it would be misleading.**
///
/// If we still need to be able to create Share's for some reason, we can simply use `pseudo_default`. We would know that the created type does not promise to make sense behaviorally; however, it is still a cheap and valid instance that can be safely dropped.
///
/// ```rust
/// use orx_pseudo_default::PseudoDefault;
///
/// struct Share {
/// number_of_shares: std::num::NonZeroUsize,
/// }
///
/// impl Share {
/// fn share_size(&self, whole_amount: usize) -> usize {
/// whole_amount / self.number_of_shares
/// }
/// }
///
/// impl PseudoDefault for Share {
/// fn pseudo_default() -> Self {
/// Self {
/// number_of_shares: std::num::NonZeroUsize::new(1).unwrap(),
/// }
/// }
/// }
/// ```
///
/// A more advanced use case could be the following. Assume that we are trying to create a vec wrapper called `TakeVec` with the following features;
/// * it allows to take out elements by index by a method called `take`
/// * we should be able to wrap an allocated vec without any additional allocation
/// * we need to be able to give back the originally allocated vec
/// * we want to achieve this without unsafe code
///
/// It is trivial to implement this with `Default` but we want to be less restrictive on the constraint so that it works for non-default types as well. We can use PseudoDefault for this.
///
/// ```rust
/// use orx_pseudo_default::PseudoDefault;
/// # struct Share {
/// # number_of_shares: std::num::NonZeroUsize,
/// # }
/// #
/// # impl Share {
/// # fn share_size(&self, whole_amount: usize) -> usize {
/// # whole_amount / self.number_of_shares
/// # }
/// # }
/// #
/// # impl PseudoDefault for Share {
/// # fn pseudo_default() -> Self {
/// # Self {
/// # number_of_shares: std::num::NonZeroUsize::new(1).unwrap(),
/// # }
/// # }
/// # }
/// struct TakeVec<T>(Vec<T>);
///
/// impl<T> From<Vec<T>> for TakeVec<T> {
/// fn from(inner: Vec<T>) -> Self {
/// Self(inner)
/// }
/// }
///
/// impl<T> From<TakeVec<T>> for Vec<T> {
/// fn from(value: TakeVec<T>) -> Self {
/// value.0
/// }
/// }
///
/// impl<T: PseudoDefault> TakeVec<T> {
/// fn take(&mut self, index: usize) -> Option<T> {
/// self.0.get_mut(index).map(|element| {
/// let mut value = T::pseudo_default();
/// std::mem::swap(&mut value, element);
/// value
/// })
/// }
/// }
///
/// // implemented default types
///
/// let mut vec: TakeVec<_> = vec![0, 1, 2, 3].into();
/// assert_eq!(vec.take(2), Some(2));
///
/// let mut vec: TakeVec<_> = vec![0.to_string(), 1.to_string()].into();
/// assert_eq!(vec.take(0), Some(String::from("0")));
///
/// // non-default types
///
/// let mut vec: TakeVec<_> = vec![
/// Share {
/// number_of_shares: std::num::NonZeroUsize::new(42).unwrap(),
/// },
/// Share {
/// number_of_shares: std::num::NonZeroUsize::new(7).unwrap(),
/// },
/// ]
/// .into();
/// assert_eq!(vec.take(0).map(|x| x.number_of_shares.into()), Some(42));
/// ```
fn pseudo_default() -> Self;
}