devela/code/
default.rs

1// devela::code::default
2//
3//!
4//
5
6/* definitions */
7
8/// A trait for giving a type a useful default value in *compile-time*.
9// WAIT: [Make Default const](https://github.com/rust-lang/rust/pull/134628)
10pub trait ConstDefault {
11    /// Returns the compile-time “default value” for a type.
12    const DEFAULT: Self;
13}
14
15// macro helper to impl ConstDefault. Supports generics.
16macro_rules! impl_cdef {
17    // <A>
18    (<$A:ident> $def:expr => $($t:ty),+) => { $( $crate::impl_cdef![@<$A> $def => $t]; )+ };
19    (@<$A:ident> $def:expr => $t:ty) => {
20        impl<$A> $crate::ConstDefault for $t {
21            #[allow(clippy::declare_interior_mutable_const)]
22            const DEFAULT: Self = $def;
23        }
24    };
25    // <A: A_> (bounded)
26    (<$A:ident:$A_:ident> $def:expr => $($t:ty),+) => {
27        $( $crate::impl_cdef![@<$A:$A_> $def => $t]; )+
28    };
29    (@<$A:ident:$A_:ident> $def:expr => $t:ty) => {
30        impl<$A: $crate::ConstDefault> $crate::ConstDefault for $t {
31            #[allow(clippy::declare_interior_mutable_const, reason = "FIXME?")]
32            const DEFAULT: Self = $def;
33        }
34    };
35    // <A, B>
36    (<$A:ident, $B:ident> $def:expr => $($t:ty),+) => {
37        $( $crate::impl_cdef![@<$A, $B> $def => $t]; )+
38    };
39    (@<$A:ident, $B:ident> $def:expr => $t:ty) => {
40        impl<$A, $B> $crate::ConstDefault for $t {
41            #[allow(clippy::declare_interior_mutable_const)] //
42            const DEFAULT: Self = $def;
43        }
44    };
45    // <A: A_, B: B_> (bounded)
46    (<$A:ident:$A_:ident, $B:ident:$B_:ident> $def:expr => $($t:ty),+) => {
47        $( $crate::impl_cdef![@<$A:$A_, $B:$B_> $def => $t]; )+ };
48    (@<$A:ident:$A_:ident, $B:ident:$B_:ident> $def:expr => $t:ty) => {
49        impl<$A:$A_, $B:$B_> $crate::ConstDefault for $t {
50            #[allow(clippy::declare_interior_mutable_const)] //
51            const DEFAULT: Self = $def;
52        }
53    };
54
55    // <A, B, C>
56    (<$A:ident, $B:ident, $C:ident> $def:expr => $($t:ty),+) => {
57        $( $crate::impl_cdef![@<$A, $B, $C> $def => $t]; )+
58    };
59    (@<$A:ident, $B:ident, $C:ident> $def:expr => $t:ty) => {
60        impl<$A, $B, $C> $crate::ConstDefault for $t {
61            #[allow(clippy::declare_interior_mutable_const)] //
62            const DEFAULT: Self = $def;
63        }
64    };
65    // <>
66    ($def:expr => $($t:ty),+) => { $( $crate::impl_cdef![@$def => $t]; )+ };
67    (@$def:expr => $t:ty) => {
68        impl $crate::ConstDefault for $t {
69            #[allow(clippy::declare_interior_mutable_const)]
70            const DEFAULT: Self = $def;
71        }
72    };
73    // impl for arrays of the given $LEN lenghts
74    (arrays <$A:ident:$BOUND:ident> $($LEN:literal),+) => {
75        $( $crate::impl_cdef![@array:$LEN <$A:$BOUND>]; )+
76    };
77    (@array:$LEN:literal <$A:ident:$BOUND:ident>) => {
78        impl<$A: $crate::ConstDefault> $crate::ConstDefault for [$A; $LEN] {
79            #[allow(clippy::declare_interior_mutable_const)] //
80            const DEFAULT: Self = [$A::DEFAULT; $LEN];
81        }
82    };
83    // impl for tuples of lenghts from 1 to 12
84    (tuples <$A:ident:$BOUND:ident>) => {
85        $crate::impl_cdef![@tuple <$A:$BOUND> ($A,) => // 1
86            ($A::DEFAULT,)];
87        $crate::impl_cdef![@tuple <$A:$BOUND> ($A,$A,) => // 2
88            ($A::DEFAULT, $A::DEFAULT)];
89        $crate::impl_cdef![@tuple <$A:$BOUND> ($A,$A,$A) => // 3
90            ($A::DEFAULT, $A::DEFAULT, $A::DEFAULT)];
91        $crate::impl_cdef![@tuple <$A:$BOUND> ($A,$A,$A,$A) => // 4
92            ($A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT)];
93        $crate::impl_cdef![@tuple <$A:$BOUND> ($A,$A,$A,$A,$A) => // 5
94            ($A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT)];
95        $crate::impl_cdef![@tuple <$A:$BOUND> ($A,$A,$A,$A,$A,$A) => // 6
96            ($A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT)];
97        $crate::impl_cdef![@tuple <$A:$BOUND> ($A,$A,$A,$A,$A,$A,$A) => // 7
98            ($A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT,
99             $A::DEFAULT)];
100        $crate::impl_cdef![@tuple <$A:$BOUND> ($A,$A,$A,$A,$A,$A,$A,$A) => // 8
101            ($A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT,
102             $A::DEFAULT, $A::DEFAULT)];
103        $crate::impl_cdef![@tuple <$A:$BOUND> ($A,$A,$A,$A,$A,$A,$A,$A,$A) => // 9
104            ($A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT,
105             $A::DEFAULT, $A::DEFAULT, $A::DEFAULT)];
106        $crate::impl_cdef![@tuple <$A:$BOUND> ($A,$A,$A,$A,$A,$A,$A,$A,$A,$A) => // 10
107            ($A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT,
108             $A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT)];
109        $crate::impl_cdef![@tuple <$A:$BOUND> ($A,$A,$A,$A,$A,$A,$A,$A,$A,$A,$A) => // 11
110            ($A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT,
111             $A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT)];
112        $crate::impl_cdef![@tuple <$A:$BOUND> ($A,$A,$A,$A,$A,$A,$A,$A,$A,$A,$A,$A) => // 12
113            ($A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT,
114             $A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT, $A::DEFAULT)];
115    };
116    (@tuple <$A:ident:$BOUND:ident> $type:ty => $value:expr) => {
117        impl<$A: $crate::ConstDefault> $crate::ConstDefault for $type {
118            const DEFAULT: Self = $value;
119        }
120    };
121}
122pub(crate) use impl_cdef;
123
124/* standard library types */
125
126#[rustfmt::skip]
127mod impl_core {
128    use super::{impl_cdef, ConstDefault};
129    use core::{
130        cmp::Reverse,
131        cell::{Cell, OnceCell, RefCell, UnsafeCell},
132        ffi::CStr,
133        marker::{PhantomData, PhantomPinned},
134        mem::ManuallyDrop,
135        num::{Saturating, Wrapping},
136        ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive},
137        panic::AssertUnwindSafe,
138        // sync::Exclusive,
139        time::Duration,
140    };
141    // Types that don't implement `Default`:
142    // ops::{Bound, ControlFlow, CoroutineState, FpCategory, Ordering, Result},
143    //
144    // NOTE: atomic types are implemented in work::sync::atomic
145
146    impl_cdef![false => bool];
147    impl_cdef![Duration::new(0, 0) => Duration];
148    impl_cdef![0 => i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize];
149    impl_cdef![0.0 => f32, f64];
150    impl_cdef!['\x00' => char];
151    impl_cdef![() => ()];
152    impl_cdef![tuples <T: ConstDefault>];
153    impl_cdef![arrays <T: ConstDefault> 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
154    13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32];
155
156    impl_cdef![<T> core::ptr::null() => *const T];
157    impl_cdef![<T> core::ptr::null_mut() => *mut T];
158
159    impl_cdef![<T> &[] => &[T]]; // not allowed for &mut [T]
160
161    impl ConstDefault for &CStr {
162        const DEFAULT: Self = {
163            if let Ok(s) = CStr::from_bytes_until_nul(&[0]) { s } else { unreachable![]; }
164        };
165    }
166
167    impl_cdef![Self => PhantomPinned, RangeFull];
168    impl_cdef![<T: ConstDefault>Self { start: T::DEFAULT } => RangeFrom<T>];
169    impl_cdef![<T: ConstDefault>Self { end: T::DEFAULT } => RangeTo<T>, RangeToInclusive<T>];
170    impl_cdef![<T: ConstDefault>Self { start: T::DEFAULT, end: T::DEFAULT } => Range<T>];
171    // this one has private fields
172    impl_cdef![<T: ConstDefault>Self::new(T::DEFAULT, T::DEFAULT) => RangeInclusive<T>];
173
174    impl_cdef![<T: ConstDefault> Self::new() => OnceCell<T>];
175    impl_cdef![<T: ConstDefault> Self::new(T::DEFAULT) =>
176        Cell<T>, ManuallyDrop<T>, RefCell<T>, UnsafeCell<T>
177    ];
178    impl_cdef![<T: ConstDefault> Self(T::DEFAULT) =>
179        AssertUnwindSafe<T>, Reverse<T>, Saturating<T>, Wrapping<T>
180    ];
181    impl_cdef![<T> Self => PhantomData<T>]; // no need for T: ConstDefault here
182    impl_cdef![<T: ConstDefault> Some(T::DEFAULT) => Option<T>];
183
184    // WAIT: [exclusive_wrapper](https://github.com/rust-lang/rust/issues/98407)
185    // impl_cdef![<T: ConstDefault> Self::new(T::DEFAULT) => Exclusive<T>];
186    // WAIT: [sync_unsafe_cell](https://github.com/rust-lang/rust/issues/95439)
187    // impl_cdef![<T> Self::new(|| T::DEFAULT) => SyncUnsafeCell<T>];
188    // WAIT: [ptr_alignment_type](https://github.com/rust-lang/rust/issues/102070)
189    // impl_cdef![<T> Self::MIN => Alignment];
190}
191
192// #[cfg(feature = "alloc")]
193// #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "alloc")))]
194// mod impl_alloc {
195//     // TODO: fxhash, fnv, ahash
196//     // #[cfg(feature = "dep_hashbrown")]
197//     // impl_cdef![<K, V> Self::with_hasher(TODO) => HashMap<K, V>];
198//     // #[cfg(feature = "dep_hashbrown")]
199//     // impl_cdef![<K> Self::with_hasher(TODO) => HashSet<K>];
200// }
201
202#[cfg(feature = "std")]
203#[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "std")))]
204mod impl_std {
205    use std::{
206        cell::LazyCell,
207        // collections::hash_map::DefaultHasher
208        // io::{Cursor, Empty, Sink},
209        process::ExitCode,
210        sync::{Condvar, LazyLock, Mutex, Once, OnceLock, RwLock, Weak as ArcWeak},
211    };
212    // Types that don't implement Default:
213    // - OsString: OsString { inner: Buf::from_string(String::new()) }
214
215    impl_cdef![Self::SUCCESS => ExitCode];
216    impl_cdef![Self::new() => Condvar, Once];
217    impl_cdef![<T: ConstDefault> Self::new() => ArcWeak<T>, OnceLock<T>];
218    impl_cdef![<T: ConstDefault> Self::new(T::DEFAULT) => Mutex<T>, RwLock<T>];
219    impl_cdef![<T: ConstDefault> Self::new(|| T::DEFAULT) => LazyCell<T>, LazyLock<T>];
220
221    // WAIT: [const_hash](https://github.com/rust-lang/rust/issues/104061)
222    // #[cfg(feature = "dep_hashbrown")]
223    // impl_cdef![<K, V> Self::with_hasher(DefaulHashher) => BTreeMap<K, V>];
224    // WAIT: [const_io_structs](https://github.com/rust-lang/rust/issues/78812)
225    // impl_cdef![Self => Cursor, Empty, Sink];
226}