leer/lib.rs
1//! Trait to abstract over types that have a notion of “being empty” and can
2//! create such an empty instance. See [`Empty`]. Intended to be a foundational
3//! crate.
4//!
5//!
6//! ## Examples
7//!
8//! Using the trait:
9//!
10//! ```
11//! use leer::Empty;
12//!
13//! let v = String::empty();
14//! ```
15//!
16//! Mostly useful for something like this:
17//!
18//! ```
19//! use leer::Empty;
20//!
21//! // Of course, in this specific case, `FromIterator` would be better. But
22//! // you get the point.
23//! fn one_two_three<C: Empty + Extend<u32>>() -> C {
24//! let mut out = C::empty();
25//! out.extend([1, 2, 3]);
26//! out
27//! }
28//!
29//! let vec: Vec<_> = one_two_three();
30//! let vec: std::collections::LinkedList<_> = one_two_three();
31//! ```
32//!
33//! ## Crate features
34//!
35//! - `derive`: if enabled, you can `#[derive(Empty)]` for structs.
36//!
37
38/// Types that have a notion of “being empty” and can create such an empty
39/// instance.
40///
41/// This is very similar to `Default` from the standard library, but makes it
42/// explicit that the returned instance is *empty* and not just any default
43/// instance. This trait is implemented for several standard types.
44pub trait Empty {
45 /// Returns an empty value of this type.
46 fn empty() -> Self;
47}
48
49/// Derive macro for [`Empty`].
50///
51/// This can only be derived for structs. All struct fields need to implement
52/// `Empty` in order for the derive to work. If your struct has generic
53/// parameters, they won't be bounded with `Empty` in the generated impl block.
54/// This is useful most of the time, because things like `Vec<T>` and
55/// `Option<T>` don't require `T: Empty` to implement `Empty`. But this means
56/// that you sometimes have to add a global `Empty` bound to your parameter or
57/// implement `Empty` manually.
58///
59/// ## Examples
60///
61/// ```
62/// use leer::Empty;
63///
64/// #[derive(Empty)]
65/// struct Zoo {
66/// foxes: Vec<Fox>,
67/// elephants: Vec<Elephant>,
68/// }
69///
70/// struct Fox;
71/// struct Elephant;
72///
73///
74/// let empty_zoo = Zoo::empty();
75/// ```
76///
77///
78/// ```
79/// use leer::Empty;
80///
81/// #[derive(Empty)]
82/// struct MyStruct {
83/// a: Vec<u32>, // => `vec![]`
84/// b: Option<String>, // => `None`
85/// c: (), // => `()`
86/// }
87/// ```
88#[cfg(feature = "derive")]
89pub use leer_macros::Empty;
90
91
92// ===========================================================================
93// ===== Implementations
94// ===========================================================================
95macro_rules! impl_empty_via_default {
96 ($( { $($impl_header:tt)+ } ,)*) => {
97 $(
98 $($impl_header)* {
99 fn empty() -> Self {
100 Self::default()
101 }
102 }
103 )*
104 }
105}
106
107impl_empty_via_default!(
108 { impl Empty for () },
109 { impl<T: ?Sized> Empty for std::marker::PhantomData<T> },
110 { impl<T> Empty for Option<T> },
111 { impl Empty for String },
112 { impl<T> Empty for Vec<T> },
113 { impl<T: Ord> Empty for std::collections::BTreeSet<T> },
114 { impl<T: Eq + std::hash::Hash> Empty for std::collections::HashSet<T> },
115 { impl<T> Empty for std::collections::LinkedList<T> },
116 { impl<T> Empty for std::collections::VecDeque<T> },
117 { impl<K: Ord, V> Empty for std::collections::BTreeMap<K, V> },
118 { impl<K: Eq + std::hash::Hash, V> Empty for std::collections::HashMap<K, V> },
119);
120
121impl<T: Empty> Empty for Box<T> {
122 fn empty() -> Self {
123 Box::new(T::empty())
124 }
125}
126
127impl<A: Empty> Empty for (A,) {
128 fn empty() -> Self { (A::empty(),) }
129}
130impl<A: Empty, B: Empty> Empty for (A, B) {
131 fn empty() -> Self { (A::empty(), B::empty()) }
132}
133impl<A: Empty, B: Empty, C: Empty> Empty for (A, B, C) {
134 fn empty() -> Self { (A::empty(), B::empty(), C::empty()) }
135}
136impl<A: Empty, B: Empty, C: Empty, D: Empty> Empty for (A, B, C, D) {
137 fn empty() -> Self { (A::empty(), B::empty(), C::empty(), D::empty()) }
138}
139
140impl<T: Empty, const N: usize> Empty for [T; N] {
141 fn empty() -> Self {
142 std::array::from_fn(|_| T::empty())
143 }
144}