1#![cfg_attr(
117 feature = "nightly",
118 feature(ascii_char, ascii_char_variants, f16, f128)
119)]
120
121#[cfg(feature = "derive")]
122extern crate is_default_derive;
123#[cfg(feature = "derive")]
124pub use is_default_derive::IsDefault;
125
126pub trait IsDefault {
128 fn is_default(&self) -> bool;
130}
131
132#[cfg(feature = "nightly")]
133use std::ascii::Char;
134
135use std::{
136 borrow::Cow,
137 cell::{Cell, OnceCell, RefCell},
138 collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque},
139 ffi::{CStr, CString, OsStr, OsString},
140 io::Cursor,
141 num::Wrapping,
142 ops::Deref,
143 path::{Path, PathBuf},
144 rc::Rc,
145 sync::{
146 Arc, Mutex, OnceLock, RwLock, Weak,
147 atomic::{
148 AtomicBool, AtomicI8, AtomicI16, AtomicI32, AtomicI64, AtomicIsize, AtomicU8,
149 AtomicU16, AtomicU32, AtomicU64, AtomicUsize, Ordering,
150 },
151 },
152 time::Duration,
153};
154
155macro_rules! unit_impl {
156 ($t:ty) => {
157 impl IsDefault for $t {
158 #[doc = concat!("assert!(", stringify!($t), ".is_default());")]
162 #[inline(always)]
164 fn is_default(&self) -> bool {
165 true
166 }
167 }
168 };
169}
170
171unit_impl!(());
172unit_impl!(std::marker::PhantomPinned);
173
174macro_rules! matches_impl {
175 ($t:ty, $v:expr; $( $not:expr ),* ) => {
176 impl IsDefault for $t {
177 #[doc = concat!("Returns `true` if self is `", stringify!($v), "`.")]
178 #[doc = concat!("assert!(", stringify!($v), ".is_default());")]
182 #[doc = concat!("assert!(", stringify!($t), "::default().is_default());")]
183 $( #[doc = concat!("assert!(!", stringify!($not), ".is_default());")] )*
184 #[inline(always)]
186 fn is_default(&self) -> bool {
187 matches!(self, $v)
188 }
189 }
190 };
191}
192
193matches_impl!(bool, false; true);
194matches_impl!(char, '\x00'; 'a', char::MAX);
195
196matches_impl!(usize, 0usize; 1usize, usize::MAX);
197matches_impl!(u8, 0u8; 1u8, u8::MAX);
198matches_impl!(u16, 0u16; 1u16, u16::MAX);
199matches_impl!(u32, 0u32; 1u32, u32::MAX);
200matches_impl!(u64, 0u64; 1u64, u64::MAX);
201matches_impl!(u128, 0u128; 1u128, u128::MAX);
202
203matches_impl!(isize, 0isize; isize::MIN, 1isize, isize::MAX);
204matches_impl!(i8, 0i8; i8::MIN, 1i8, i8::MAX);
205matches_impl!(i16, 0i16; i16::MIN, 1i16, i16::MAX);
206matches_impl!(i32, 0i32; i32::MIN, 1i32, i32::MAX);
207matches_impl!(i64, 0i64; i64::MIN, 1i64, i64::MAX);
208matches_impl!(i128, 0i128; i128::MIN, 1i128, i128::MAX);
209
210matches_impl!(f32, 0f32; f32::MIN, 1f32, f32::MAX);
211matches_impl!(f64, 0f64; f64::MIN, 1f64, f64::MAX);
212
213impl<T> IsDefault for Wrapping<T>
214where
215 T: IsDefault,
216{
217 #[inline(always)]
226 fn is_default(&self) -> bool {
227 self.0.is_default()
228 }
229}
230
231macro_rules! nightly_matches_impl {
232 ($t:ty, $v:expr $(, $nightly_fs:literal)? ; $( $not:expr ),* ) => {
233 #[cfg(feature = "nightly")]
234 impl IsDefault for $t {
235 #[doc = concat!("Returns `true` if self is `", stringify!($v), "`.")]
236 $( #[doc = concat!("#![cfg_attr(feature = \"nightly\", feature(", $nightly_fs, "))]")] )?
238 #[doc = concat!("assert!(", stringify!($v), ".is_default());")]
241 #[doc = concat!("assert!(", stringify!($t), "::default().is_default());")]
242 $( #[doc = concat!("assert!(!", stringify!($not), ".is_default());")] )*
243 #[inline(always)]
245 fn is_default(&self) -> bool {
246 matches!(self, $v)
247 }
248 }
249 };
250}
251
252nightly_matches_impl!(f16, 0f16, "f16"; f16::MIN, 1f16, f16::MAX);
253nightly_matches_impl!(f128, 0f128, "f128"; f128::MIN, 1f128, f128::MAX);
254
255#[cfg(feature = "nightly")]
256impl IsDefault for Char {
257 #[inline(always)]
268 fn is_default(&self) -> bool {
269 matches!(self, Char::Null)
270 }
271}
272
273macro_rules! atomic_impl {
274 ($t:ty, $v:expr; $( $not:expr ),* ) => {
275 impl IsDefault for $t {
276 #[doc = concat!("Returns `true` if the inner value is `", stringify!($v), "`.")]
277 #[doc = concat!("use std::sync::atomic::{", stringify!($t), ", Ordering};")]
280 #[doc = concat!("assert!(", stringify!($t), "::new(", stringify!($v), ").is_default());")]
282 #[doc = concat!("assert!(", stringify!($t), "::default().is_default());")]
283 $( #[doc = concat!("assert!(!", stringify!($t), "::new(", stringify!($not), ").is_default());")] )*
284 #[inline(always)]
286 fn is_default(&self) -> bool {
287 matches!(self.load(Ordering::Relaxed), $v)
288 }
289 }
290 };
291}
292
293atomic_impl!(AtomicBool, false; true);
294
295atomic_impl!(AtomicI8, 0; i8::MIN, 1, i8::MAX);
296atomic_impl!(AtomicI16, 0; i16::MIN, 1, i16::MAX);
297atomic_impl!(AtomicI32, 0; i32::MIN, 1, i32::MAX);
298atomic_impl!(AtomicI64, 0; i64::MIN, 1, i64::MAX);
299atomic_impl!(AtomicIsize, 0; isize::MIN, 1, isize::MAX);
300
301atomic_impl!(AtomicU8, 0; 1, u8::MAX);
302atomic_impl!(AtomicU16, 0; 1, u16::MAX);
303atomic_impl!(AtomicU32, 0; 1, u32::MAX);
304atomic_impl!(AtomicU64, 0; 1, u64::MAX);
305atomic_impl!(AtomicUsize, 0; 1, usize::MAX);
306
307macro_rules! str_impl {
308 ($t:ty, $v:expr $(, $use:literal)? ; $not:expr) => {
309 impl IsDefault for $t {
310 $( #[doc = concat!("use std::ffi::", $use, ";")] )?
314 #[doc = concat!("assert!(", stringify!($v), ".is_default());")]
316 #[doc = concat!("assert!(!", stringify!($not), ".is_default());")]
317 #[inline(always)]
319 fn is_default(&self) -> bool {
320 self.is_empty()
321 }
322 }
323 };
324}
325
326str_impl!(str, ""; "x");
327str_impl!(String, String::from(""); String::from("x"));
328str_impl!(CStr, c""; c"x");
329str_impl!(CString, CString::from(c""), "CString"; CString::from(c"x"));
330str_impl!(OsStr, OsStr::new(""), "OsStr"; OsStr::new("x"));
331str_impl!(OsString, OsString::from(""), "OsString"; OsString::from("x"));
332
333macro_rules! path_impl {
334 ($t:ty, $new:literal) => {
335 impl IsDefault for $t {
336 #[doc = concat!("use std::path::", stringify!($t), ";")]
340 #[doc = concat!("assert!(", stringify!($t), "::", $new, "(\"\").is_default());\n")]
342 #[doc = concat!("assert!(!", stringify!($t), "::", $new, "(\"x\").is_default());\n")]
343 #[inline(always)]
345 fn is_default(&self) -> bool {
346 self.as_os_str().is_empty()
347 }
348 }
349 };
350}
351
352path_impl!(Path, "new");
353path_impl!(PathBuf, "from");
354
355impl IsDefault for Duration {
356 #[inline(always)]
366 fn is_default(&self) -> bool {
367 self.is_zero()
368 }
369}
370
371impl<T> IsDefault for Option<T> {
372 #[inline(always)]
381 fn is_default(&self) -> bool {
382 self.is_none()
383 }
384}
385
386macro_rules! collection_impl {
387 ($t:ident $(, $use:literal)? ) => {
388 impl<T> IsDefault for $t<T> {
389 $( #[doc = concat!("use std::collections::", $use, ";")] )?
393 #[doc = concat!("assert!(", stringify!($t), "::<u8>::default().is_default());")]
395 #[doc = concat!("assert!(!", stringify!($t), "::from([0u8]).is_default());")]
396 #[inline(always)]
398 fn is_default(&self) -> bool {
399 self.is_empty()
400 }
401 }
402 };
403}
404
405collection_impl!(Vec);
406collection_impl!(BTreeSet, "BTreeSet");
407collection_impl!(BinaryHeap, "BinaryHeap");
408collection_impl!(HashSet, "HashSet");
409collection_impl!(LinkedList, "LinkedList");
410collection_impl!(VecDeque, "VecDeque");
411
412macro_rules! map_impl {
413 ($t:ident) => {
414 impl<K, V> IsDefault for $t<K, V> {
415 #[doc = concat!("use std::collections::", stringify!($t), ";")]
419 #[doc = concat!("assert!(", stringify!($t), "::<u8, u8>::default().is_default());")]
421 #[doc = concat!("assert!(!", stringify!($t), "::from([(0u8, 0u8)]).is_default());")]
422 #[inline(always)]
424 fn is_default(&self) -> bool {
425 self.is_empty()
426 }
427 }
428 };
429}
430
431map_impl!(BTreeMap);
432map_impl!(HashMap);
433
434macro_rules! pointer_impl {
435 ($t:ident $(, $use:literal)? ) => {
436 impl<T> IsDefault for $t<T>
437 where
438 T: IsDefault,
439 {
440 $( #[doc = concat!("use ", $use, ";")] )?
444 #[doc = concat!("assert!(", stringify!($t), "::new(0u8).is_default());")]
446 #[doc = concat!("assert!(", stringify!($t), "::<u8>::default().is_default());")]
447 #[doc = concat!("assert!(!", stringify!($t), "::new(1u8).is_default());")]
448 #[inline(always)]
450 fn is_default(&self) -> bool {
451 (**self).is_default()
452 }
453 }
454 };
455}
456
457pointer_impl!(Arc, "std::sync::Arc");
458pointer_impl!(Box);
459pointer_impl!(Rc, "std::rc::Rc");
460
461impl<T> IsDefault for Cow<'_, T>
462where
463 T: IsDefault + ToOwned + ?Sized,
464{
465 #[inline(always)]
474 fn is_default(&self) -> bool {
475 self.deref().is_default()
476 }
477}
478
479macro_rules! lock_impl {
480 ($t:ident, $lock:ident, $use:literal) => {
481 impl<T> IsDefault for $t<T>
482 where
483 T: IsDefault,
484 {
485 #[doc = concat!("Always return false if `self.", stringify!($lock), "()` returns an error.")]
487 #[doc = concat!("use ", $use, "::", stringify!($t), ";")]
490 #[doc = concat!(
492 "assert!(", stringify!($t), "::new(0u8).", stringify!($lock) , "().unwrap().is_default());"
493 )]
494 #[doc = concat!(
495 "assert!(", stringify!($t), "::<u8>::default().", stringify!($lock) , "().unwrap().is_default());"
496 )]
497 #[doc = concat!(
498 "assert!(!", stringify!($t), "::new(1u8).", stringify!($lock) , "().unwrap().is_default());"
499 )]
500 #[inline(always)]
502 fn is_default(&self) -> bool {
503 self.$lock().map_or(false, |v| v.is_default())
504 }
505 }
506 };
507}
508
509lock_impl!(RefCell, try_borrow, "std::cell");
510lock_impl!(RwLock, try_read, "std::sync");
511lock_impl!(Mutex, try_lock, "std::sync");
512
513impl<T> IsDefault for Cell<T>
514where
515 T: Copy + IsDefault,
516{
517 #[inline(always)]
526 fn is_default(&self) -> bool {
527 self.get().is_default()
528 }
529}
530
531macro_rules! once_impl {
532 ($t:ident, $use:literal) => {
533 impl<T> IsDefault for $t<T> {
534 #[doc = concat!("use ", $use, "::", stringify!($t), ";")]
538 #[doc = concat!("let v = ", stringify!($t), "::<u8>::new();")]
540 #[inline(always)]
545 fn is_default(&self) -> bool {
546 matches!(self.get(), None)
547 }
548 }
549 };
550}
551
552once_impl!(OnceCell, "std::cell");
553once_impl!(OnceLock, "std::sync");
554
555impl<T> IsDefault for Weak<T> {
556 #[inline(always)]
569 fn is_default(&self) -> bool {
570 matches!(self.upgrade(), None)
571 }
572}
573
574impl<T> IsDefault for Cursor<T> {
575 #[inline(always)]
586 fn is_default(&self) -> bool {
587 matches!(self.position(), 0u64)
588 }
589}
590
591impl<T> IsDefault for [T]
592where
593 T: IsDefault,
594{
595 #[inline(always)]
605 fn is_default(&self) -> bool {
606 if self.is_empty() {
607 true
608 } else {
609 self.iter().all(|x| x.is_default())
610 }
611 }
612}
613
614impl<T, const N: usize> IsDefault for [T; N]
615where
616 T: IsDefault,
617{
618 #[inline(always)]
628 fn is_default(&self) -> bool {
629 self.as_slice().is_default()
630 }
631}
632
633impl<T> IsDefault for &T
634where
635 T: IsDefault + ?Sized,
636{
637 #[inline(always)]
656 fn is_default(&self) -> bool {
657 (**self).is_default()
658 }
659}
660
661impl<T> IsDefault for &mut T
662where
663 T: IsDefault + ?Sized,
664{
665 #[inline(always)]
684 fn is_default(&self) -> bool {
685 (**self).is_default()
686 }
687}