orx_pseudo_default/
lib.rs

1//! # orx-pseudo-default
2//!
3//! [![orx-pseudo-default crate](https://img.shields.io/crates/v/orx-pseudo-default.svg)](https://crates.io/crates/orx-pseudo-default)
4//! [![orx-pseudo-default documentation](https://docs.rs/orx-pseudo-default/badge.svg)](https://docs.rs/orx-pseudo-default)
5//!
6//! `PseudoDefault` trait allows to create a cheap default instance of a type, which **does not claim to be useful**.
7//!
8//! The difference of `PseudoDefault` from `Default` is the relaxed expectation of the created instance to be useful.
9//!
10//! 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.
11//!
12//! This trait allows to avoid unsafe code in certain use cases. For instance:
13//! * 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.
14//! * 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.
15//!
16//! Note that pseudo-default requirement is more relaxed than that of default, and hence,
17//! * types implementing Default can implement PseudoDefault,
18//! * 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.
19//!
20//! # Example
21//!
22//! 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.
23//!
24//! **Therefore, we cannot justify implementing `Default`, it would be misleading.**
25//!
26//! 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.
27//!
28//! ```rust
29//! use orx_pseudo_default::PseudoDefault;
30//!
31//! struct Share {
32//!     number_of_shares: std::num::NonZeroUsize,
33//! }
34//!
35//! impl Share {
36//!     fn share_size(&self, whole_amount: usize) -> usize {
37//!         whole_amount / self.number_of_shares
38//!     }
39//! }
40//!
41//! impl PseudoDefault for Share {
42//!     fn pseudo_default() -> Self {
43//!         Self {
44//!             number_of_shares: std::num::NonZeroUsize::new(1).unwrap(),
45//!         }
46//!     }
47//! }
48//! ```
49//!
50//! 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;
51//! * it allows to take out elements by index by a method called `take`
52//! * we should be able to wrap an allocated vec without any additional allocation
53//! * we need to be able to give back the originally allocated vec
54//! * we want to achieve this without unsafe code
55//!
56//! 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.
57//!
58//! ```rust
59//! use orx_pseudo_default::PseudoDefault;
60//!
61//! struct TakeVec<T>(Vec<T>);
62//! # struct Share {
63//! #     number_of_shares: std::num::NonZeroUsize,
64//! # }
65//! #
66//! # impl Share {
67//! #     fn share_size(&self, whole_amount: usize) -> usize {
68//! #         whole_amount / self.number_of_shares
69//! #     }
70//! # }
71//! #
72//! # impl PseudoDefault for Share {
73//! #     fn pseudo_default() -> Self {
74//! #         Self {
75//! #             number_of_shares: std::num::NonZeroUsize::new(1).unwrap(),
76//! #         }
77//! #     }
78//! # }
79//!
80//! impl<T> From<Vec<T>> for TakeVec<T> {
81//!     fn from(inner: Vec<T>) -> Self {
82//!         Self(inner)
83//!     }
84//! }
85//!
86//! impl<T> From<TakeVec<T>> for Vec<T> {
87//!     fn from(value: TakeVec<T>) -> Self {
88//!         value.0
89//!     }
90//! }
91//!
92//! impl<T: PseudoDefault> TakeVec<T> {
93//!     fn take(&mut self, index: usize) -> Option<T> {
94//!         self.0.get_mut(index).map(|element| {
95//!             let mut value = T::pseudo_default();
96//!             std::mem::swap(&mut value, element);
97//!             value
98//!         })
99//!     }
100//! }
101//!
102//! // implemented default types
103//!
104//! let mut vec: TakeVec<_> = vec![0, 1, 2, 3].into();
105//! assert_eq!(vec.take(2), Some(2));
106//!
107//! let mut vec: TakeVec<_> = vec![0.to_string(), 1.to_string()].into();
108//! assert_eq!(vec.take(0), Some(String::from("0")));
109//!
110//! // non-default types
111//!
112//! let mut vec: TakeVec<_> = vec![
113//!     Share {
114//!         number_of_shares: std::num::NonZeroUsize::new(42).unwrap(),
115//!     },
116//!     Share {
117//!         number_of_shares: std::num::NonZeroUsize::new(7).unwrap(),
118//!     },
119//! ]
120//! .into();
121//! assert_eq!(vec.take(0).map(|x| x.number_of_shares.into()), Some(42));
122//! ```
123//!
124//! ### Derive
125//!
126//! Similar to `Default`, it is possible to derive `PseudoDefault` provided that all members also implement `PseudoDefault`.
127//!
128//! ```rust ignore
129//! use orx_pseudo_default::*;
130//!
131//! #[derive(PseudoDefault)]
132//! struct ChildStruct {
133//!     a: String,
134//!     b: char,
135//!     c: Vec<u32>,
136//! }
137//!
138//! #[derive(PseudoDefault)]
139//! struct MyStruct {
140//!     x: ChildStruct,
141//!     y: bool,
142//!     z: Option<usize>,
143//! }
144//!
145//! assert_eq!(String::pseudo_default(), MyStruct::pseudo_default().x.a);
146//! assert_eq!(char::pseudo_default(), MyStruct::pseudo_default().x.b);
147//! assert_eq!(Vec::<u32>::pseudo_default(), MyStruct::pseudo_default().x.c);
148//! assert_eq!(bool::pseudo_default(), MyStruct::pseudo_default().y);
149//! assert_eq!(
150//!     Option::<usize>::pseudo_default(),
151//!     MyStruct::pseudo_default().z
152//! );
153//! ```
154//!
155//! ## Contributing
156//!
157//! Contributions are welcome! If you notice an error, have a question or think something could be improved, please open an [issue](https://github.com/orxfun/orx-pseudo-default/issues/new) or create a PR.
158//!
159//! ## License
160//!
161//! This library is licensed under MIT license. See LICENSE for details.
162
163#![warn(
164    missing_docs,
165    clippy::unwrap_in_result,
166    clippy::unwrap_used,
167    clippy::panic,
168    clippy::panic_in_result_fn,
169    clippy::float_cmp,
170    clippy::float_cmp_const,
171    clippy::missing_panics_doc,
172    clippy::todo
173)]
174#![cfg_attr(not(feature = "std"), no_std)]
175
176extern crate alloc;
177
178mod implementations;
179mod pseudo_default;
180
181pub use pseudo_default::PseudoDefault;
182
183#[cfg(feature = "derive")]
184pub use orx_pseudo_default_derive::PseudoDefault;