const_default/
lib.rs

1#![doc(html_root_url = "http://docs.rs/const-default/1.0.0")]
2#![cfg_attr(not(feature = "std"), no_std)]
3#![cfg_attr(feature = "unstable-docs", feature(doc_cfg))]
4#![cfg_attr(
5	all(feature = "unstable", feature = "alloc"),
6	feature(const_btree_new)
7)]
8#![cfg_attr(feature = "unstable", feature(const_fn_trait_bound))]
9#![cfg_attr(
10	all(feature = "unstable", feature = "enable-atomics"),
11	feature(cfg_target_has_atomic)
12)]
13#![cfg_attr(
14	feature = "enable-atomics",
15	allow(clippy::declare_interior_mutable_const)
16)]
17
18#[cfg(feature = "alloc")]
19extern crate alloc;
20
21#[cfg(feature = "derive")]
22#[cfg_attr(feature = "unstable-docs", doc(cfg(feature = "derive")))]
23pub use const_default_derive::ConstDefault;
24
25/// Implements a compilation time default value for the implemented type.
26///
27/// # Note
28///
29/// Unlike the [`Default`] trait implementation the `DEFAULT` of implementations
30/// of this trait can be used in constant evaluation contexts.
31///
32/// # Example
33///
34/// ```
35/// # #[cfg(feature = "std")]
36/// # const _: () = {
37/// # use const_default::ConstDefault;
38/// const VEC: Vec<u8> = <Vec<u8> as ConstDefault>::DEFAULT;
39/// # };
40/// ```
41///
42/// The above code works while the below code does not:
43///
44/// ```compile_fail
45/// const VEC: Vec<u8> = <Vec<u8> as Default>::default();
46/// ```
47pub trait ConstDefault: Sized {
48	/// The constant default value.
49	const DEFAULT: Self;
50}
51
52/// Returns the compilation time default value for a type
53#[inline]
54#[cfg(feature = "unstable")]
55#[cfg_attr(feature = "unstable-docs", doc(cfg(feature = "unstable")))]
56pub const fn const_default<T: ConstDefault>() -> T {
57	T::DEFAULT
58}
59
60impl<T> ConstDefault for Option<T> {
61	const DEFAULT: Self = None;
62}
63
64#[cfg(feature = "alloc")]
65#[cfg_attr(
66	feature = "unstable-docs",
67	doc(cfg(any(feature = "std", feature = "alloc")))
68)]
69impl<'a, T> ConstDefault for alloc::borrow::Cow<'a, T>
70where
71	T: alloc::borrow::ToOwned + ?Sized + 'a,
72	<T as alloc::borrow::ToOwned>::Owned: ConstDefault,
73{
74	const DEFAULT: Self = Self::Owned(
75		<<T as alloc::borrow::ToOwned>::Owned as ConstDefault>::DEFAULT,
76	);
77}
78
79impl<T: ConstDefault> ConstDefault for core::cell::Cell<T> {
80	const DEFAULT: Self = Self::new(T::DEFAULT);
81}
82
83impl<T: ConstDefault> ConstDefault for core::cell::UnsafeCell<T> {
84	const DEFAULT: Self = Self::new(T::DEFAULT);
85}
86
87impl<T: ConstDefault> ConstDefault for core::cell::RefCell<T> {
88	const DEFAULT: Self = Self::new(T::DEFAULT);
89}
90
91// TODO revisit whether this makes sense?
92impl<T: ConstDefault> ConstDefault for core::mem::MaybeUninit<T> {
93	const DEFAULT: Self = Self::new(T::DEFAULT);
94}
95
96#[cfg(feature = "alloc")]
97#[cfg_attr(
98	feature = "unstable-docs",
99	doc(cfg(any(feature = "std", feature = "alloc")))
100)]
101impl<T> ConstDefault for alloc::vec::Vec<T> {
102	const DEFAULT: Self = Self::new();
103}
104
105#[cfg(feature = "alloc")]
106#[cfg_attr(
107	feature = "unstable-docs",
108	doc(cfg(any(feature = "std", feature = "alloc")))
109)]
110impl ConstDefault for alloc::string::String {
111	const DEFAULT: Self = Self::new();
112}
113
114#[cfg(all(feature = "alloc", feature = "unstable"))]
115#[cfg_attr(
116	feature = "unstable-docs",
117	doc(
118		cfg(any(feature = "std", feature = "alloc")),
119		cfg(feature = "unstable")
120	)
121)]
122impl<K: Ord, V> ConstDefault for alloc::collections::BTreeMap<K, V> {
123	const DEFAULT: Self = Self::new();
124}
125
126#[cfg(all(feature = "alloc", feature = "unstable"))]
127#[cfg_attr(
128	feature = "unstable-docs",
129	doc(
130		cfg(any(feature = "std", feature = "alloc")),
131		cfg(feature = "unstable")
132	)
133)]
134impl<T: Ord> ConstDefault for alloc::collections::BTreeSet<T> {
135	const DEFAULT: Self = Self::new();
136}
137
138#[cfg(feature = "alloc")]
139#[cfg_attr(
140	feature = "unstable-docs",
141	doc(cfg(any(feature = "std", feature = "alloc")))
142)]
143impl<T> ConstDefault for alloc::collections::LinkedList<T> {
144	const DEFAULT: Self = Self::new();
145}
146
147impl<'a, T: 'a> ConstDefault for &'a [T] {
148	const DEFAULT: Self = &[];
149}
150
151impl<T> ConstDefault for *const T {
152	const DEFAULT: Self = core::ptr::null();
153}
154
155impl<T> ConstDefault for *mut T {
156	const DEFAULT: Self = core::ptr::null_mut();
157}
158
159impl<T: ConstDefault> ConstDefault for core::mem::ManuallyDrop<T> {
160	const DEFAULT: Self = Self::new(T::DEFAULT);
161}
162
163impl<T: ?Sized> ConstDefault for core::marker::PhantomData<T> {
164	const DEFAULT: Self = Self;
165}
166
167impl ConstDefault for core::marker::PhantomPinned {
168	const DEFAULT: Self = Self;
169}
170
171impl<T> ConstDefault for core::iter::Empty<T> {
172	const DEFAULT: Self = core::iter::empty();
173}
174
175impl<T: ConstDefault> ConstDefault for core::num::Wrapping<T> {
176	const DEFAULT: Self = Self(T::DEFAULT);
177}
178
179impl ConstDefault for core::time::Duration {
180	const DEFAULT: Self = core::time::Duration::from_secs(0);
181}
182
183#[cfg(feature = "std")]
184#[cfg_attr(feature = "unstable-docs", doc(cfg(feature = "std")))]
185impl ConstDefault for std::sync::Once {
186	const DEFAULT: Self = Self::new();
187}
188
189macro_rules! impl_num {
190	($($ty:ty=$d:expr$(;$name:ident=$width:literal)?),*) => {
191		$(
192			impl ConstDefault for $ty {
193				const DEFAULT: Self = $d;
194			}
195
196			impl ConstDefault for &$ty {
197				const DEFAULT: Self = &<$ty as ConstDefault>::DEFAULT;
198			}
199
200			$(
201				#[cfg(feature = "enable-atomics")]
202				#[cfg_attr(feature = "unstable-docs", doc(cfg(any(feature = "default", feature = "enable-atomics"))))]
203				#[cfg_attr(feature = "unstable", cfg(target_has_atomic = $width))]
204				impl ConstDefault for core::sync::atomic::$name {
205					const DEFAULT: Self = Self::new(ConstDefault::DEFAULT);
206				}
207			)?
208		)*
209	};
210}
211
212impl_num! {
213	()=(), bool=false, f32=0.0, f64=0.0, char='\x00', &str="",
214	u8=0;AtomicU8="8", u16=0;AtomicU16="16", u32=0;AtomicU32="32", u64=0;AtomicU64="64", usize=0;AtomicUsize="ptr",
215	i8=0;AtomicI8="8", i16=0;AtomicI16="16", i32=0;AtomicI32="32", i64=0;AtomicI64="64", isize=0;AtomicIsize="ptr",
216	i128=0, u128=0
217}
218
219#[cfg(feature = "enable-atomics")]
220#[cfg_attr(
221	feature = "unstable-docs",
222	doc(cfg(any(feature = "default", feature = "enable-atomics")))
223)]
224#[cfg_attr(feature = "unstable", cfg(target_has_atomic = "8"))]
225impl ConstDefault for core::sync::atomic::AtomicBool {
226	const DEFAULT: Self = Self::new(ConstDefault::DEFAULT);
227}
228
229#[cfg(feature = "enable-atomics")]
230#[cfg_attr(
231	feature = "unstable-docs",
232	doc(cfg(any(feature = "default", feature = "enable-atomics")))
233)]
234#[cfg_attr(feature = "unstable", cfg(target_has_atomic = "ptr"))]
235impl<T> ConstDefault for core::sync::atomic::AtomicPtr<T> {
236	const DEFAULT: Self = Self::new(core::ptr::null_mut());
237}
238
239macro_rules! impl_tuple {
240	(@rec $t:ident) => { };
241	(@rec $_:ident $($t:ident)+) => {
242		impl_tuple! { @impl $($t)* }
243		impl_tuple! { @rec $($t)* }
244	};
245	(@impl $($t:ident)*) => {
246		impl<$($t: ConstDefault,)*> ConstDefault for ($($t,)*) {
247			const DEFAULT: Self = ($($t::DEFAULT,)*);
248		}
249	};
250	($($t:ident)*) => {
251		impl_tuple! { @rec _t $($t)* }
252	};
253}
254
255impl_tuple! {
256	A B C D E F G H I J K L
257}
258
259impl<T: ConstDefault, const N: usize> ConstDefault for [T; N] {
260	const DEFAULT: Self = [T::DEFAULT; N];
261}