| Crates.io | orx-pseudo-default |
| lib.rs | orx-pseudo-default |
| version | 2.1.0 |
| created_at | 2024-07-23 19:17:56.963918+00 |
| updated_at | 2025-04-06 17:40:10.407921+00 |
| description | PseudoDefault trait allows to create a cheap default instance of a type, which does not claim to be useful. |
| homepage | |
| repository | https://github.com/orxfun/orx-pseudo-default/ |
| max_upload_size | |
| id | 1313194 |
| size | 45,419 |
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:
Note that pseudo-default requirement is more relaxed than that of default, and hence,
no-std: This crate supports no-std; however, std is added as a default feature together with derive. Please include with no-default-features for no-std use cases:
cargo add orx-pseudo-default --no-default-features.
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.
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;
takeIt 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.
use orx_pseudo_default::PseudoDefault;
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
struct Share {
number_of_shares: std::num::NonZeroUsize,
}
impl PseudoDefault for Share {
fn pseudo_default() -> Self {
Self {
number_of_shares: std::num::NonZeroUsize::new(1).unwrap(),
}
}
}
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));
Similar to Default, it is possible to derive PseudoDefault provided that all members also implement PseudoDefault.
use orx_pseudo_default::*;
#[derive(PseudoDefault)]
struct ChildStruct {
a: String,
b: char,
c: Vec<u32>,
}
#[derive(PseudoDefault)]
struct MyStruct {
x: ChildStruct,
y: bool,
z: Option<usize>,
}
assert_eq!(String::pseudo_default(), MyStruct::pseudo_default().x.a);
assert_eq!(char::pseudo_default(), MyStruct::pseudo_default().x.b);
assert_eq!(Vec::<u32>::pseudo_default(), MyStruct::pseudo_default().x.c);
assert_eq!(bool::pseudo_default(), MyStruct::pseudo_default().y);
assert_eq!(
Option::<usize>::pseudo_default(),
MyStruct::pseudo_default().z
);
Contributions are welcome! If you notice an error, have a question or think something could be improved, please open an issue or create a PR.
Dual-licensed under Apache 2.0 or MIT.