is_default/
lib.rs

1//! # IsDefault
2//!
3//! A trait for checking if a value is default, with easy derive support for custom types.
4//!
5//! Example, instead of `is_none` for [`Option`] and `is_empty` for [`Vec`]
6//! can be used `is_default` for all.
7//!
8//! ```rust
9//! assert!(None::<u8>.is_none());
10//! assert!(Vec::<u8>::new().is_empty());
11//!
12//! use is_default::IsDefault;
13//! assert!(None::<u8>.is_default());
14//! assert!(Vec::<u8>::new().is_default());
15//! ```
16//!
17//! The `IsDefault` trait is implemented for most standard types that
18//! has `Default` impl. With the `derive` feature, you can easily generate
19//! implementations for your own types:
20//!
21//! ## Derive
22//!
23//! To use the derive macro, add the dependency with the `derive` feature
24//! in your `Cargo.toml`:
25//!
26//! ```toml
27//! # Cargo.toml
28//!
29//! [dependencies]
30//! is_default = { version = "0.1", features = ["derive"] }
31//! ```
32//!
33//! ### Structs
34//!
35//! A struct can derive `IsDefault` if all its fields implement `IsDefault`.
36//!
37//! ```rust
38//! # #[cfg(feature = "derive")] {
39//! use is_default::IsDefault;
40//!
41//! #[derive(IsDefault)]
42//! struct Unit;
43//! assert!(Unit.is_default());
44//!
45//! #[derive(IsDefault)]
46//! struct Wrapper(u8);
47//! assert!(Wrapper(0).is_default());
48//! assert!(!Wrapper(1).is_default());
49//!
50//! #[derive(IsDefault)]
51//! struct Point { x: i16, y: f32 }
52//! assert!(Point{ x: 0, y: 0.0 }.is_default());
53//! assert!(!Point{ x: 1, y: 0.0 }.is_default());
54//! assert!(!Point{ x: 0, y: 1.1 }.is_default());
55//! # }
56//! ```
57//!
58//! ### Enums
59//!
60//! When using #[derive(IsDefault)] on an enum, you need to choose which
61//! unit variant will be default. You do this by placing the #[is_default]
62//! OR #[default] attribute on the variant.
63//!
64//! This makes it possible to derive both `Default` and `IsDefault` using
65//! the same attribute.
66//!
67//! ```rust
68//! # #[cfg(feature = "derive")] {
69//! use is_default::IsDefault;
70//!
71//! #[derive(IsDefault)]
72//! enum A {
73//!     #[is_default]
74//!     X,
75//!     Y,
76//! }
77//! assert!(A::X.is_default());
78//! assert!(!A::Y.is_default());
79//!
80//! #[derive(Default, IsDefault)]
81//! enum B {
82//!     X,
83//!     #[default]
84//!     Y,
85//! }
86//! assert!(!B::X.is_default());
87//! assert!(B::Y.is_default());
88//! assert!(matches!(B::default(), B::Y));
89//! # }
90//! ```
91//!
92//! Also #[derive(IsDefault)] on an enum possible if it implements both
93//! `Default` and `PartialEq`. However, this implementation may be
94//! inefficient, since a new `Self` object must be allocated for comparison.
95//!
96//! ```rust
97//! # #[cfg(feature = "derive")] {
98//! use is_default::IsDefault;
99//!
100//! #[derive(PartialEq, IsDefault)]
101//! enum C {
102//!     X(u8),
103//!     Y,
104//! }
105//! impl Default for C {
106//!     fn default() -> C {
107//!         C::X(0)
108//!     }
109//! }
110//!
111//! assert!(C::X(0).is_default());
112//! assert!(!C::X(1).is_default());
113//! # }
114//! ```
115
116#![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
126/// Checks whether a value is equal to its type's default.
127pub trait IsDefault {
128    /// Returns `true` if `self` is equal to the default value for its type.
129    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            /// Always returns `true`.
159            /// ```
160            /// use is_default::IsDefault;
161            #[doc = concat!("assert!(", stringify!($t), ".is_default());")]
162            /// ```
163            #[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            /// ```
179            /// use is_default::IsDefault;
180            ///
181            #[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            /// ```
185            #[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    /// Returns `true` if the inner value is default.
218    /// ```
219    /// use is_default::IsDefault;
220    /// use std::num::Wrapping;
221    ///
222    /// assert!(Wrapping(0u8).is_default());
223    /// assert!(!Wrapping(1u8).is_default());
224    /// ```
225    #[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            /// ```
237            $( #[doc = concat!("#![cfg_attr(feature = \"nightly\", feature(", $nightly_fs, "))]")] )?
238            /// use is_default::IsDefault;
239            ///
240            #[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            /// ```
244            #[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    /// Returns `true` if self is `Char::Null`.
258    /// ```
259    /// #![cfg_attr(feature = "nightly", feature(ascii_char, ascii_char_variants))]
260    /// use is_default::IsDefault;
261    /// use std::ascii::Char;
262    ///
263    /// assert!(Char::Null.is_default());
264    /// assert!(Char::default().is_default());
265    /// assert!(!Char::StartOfHeading.is_default());
266    /// ```
267    #[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            /// ```
278            /// use is_default::IsDefault;
279            #[doc = concat!("use std::sync::atomic::{", stringify!($t), ", Ordering};")]
280            ///
281            #[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            /// ```
285            #[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            /// Returns `true` if self is empty.
311            /// ```
312            /// use is_default::IsDefault;
313            $( #[doc = concat!("use std::ffi::", $use, ";")] )?
314            ///
315            #[doc = concat!("assert!(", stringify!($v), ".is_default());")]
316            #[doc = concat!("assert!(!", stringify!($not), ".is_default());")]
317            /// ```
318            #[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            /// Returns `true` if self is empty.
337            /// ```
338            /// use is_default::IsDefault;
339            #[doc = concat!("use std::path::", stringify!($t), ";")]
340            ///
341            #[doc = concat!("assert!(", stringify!($t), "::", $new, "(\"\").is_default());\n")]
342            #[doc = concat!("assert!(!", stringify!($t), "::", $new, "(\"x\").is_default());\n")]
343            /// ```
344            #[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    /// Returns `true` if self is zero.
357    /// ```
358    /// use is_default::IsDefault;
359    /// use std::time::Duration;
360    ///
361    /// assert!(Duration::ZERO.is_default());
362    /// assert!(Duration::default().is_default());
363    /// assert!(!Duration::new(1, 0).is_default());
364    /// ```
365    #[inline(always)]
366    fn is_default(&self) -> bool {
367        self.is_zero()
368    }
369}
370
371impl<T> IsDefault for Option<T> {
372    /// Returns `true` if self is none.
373    /// ```
374    /// use is_default::IsDefault;
375    ///
376    /// assert!(None::<u8>.is_default());
377    /// assert!(Option::<u8>::default().is_default());
378    /// assert!(!Some(0u8).is_default());
379    /// ```
380    #[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            /// Returns `true` if self is empty.
390            /// ```
391            /// use is_default::IsDefault;
392            $( #[doc = concat!("use std::collections::", $use, ";")] )?
393            ///
394            #[doc = concat!("assert!(", stringify!($t), "::<u8>::default().is_default());")]
395            #[doc = concat!("assert!(!", stringify!($t), "::from([0u8]).is_default());")]
396            /// ```
397            #[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            /// Returns `true` if self is empty.
416            /// ```
417            /// use is_default::IsDefault;
418            #[doc = concat!("use std::collections::", stringify!($t), ";")]
419            ///
420            #[doc = concat!("assert!(", stringify!($t), "::<u8, u8>::default().is_default());")]
421            #[doc = concat!("assert!(!", stringify!($t), "::from([(0u8, 0u8)]).is_default());")]
422            /// ```
423            #[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            /// Returns `true` if the inner value is default.
441            /// ```
442            /// use is_default::IsDefault;
443            $( #[doc = concat!("use ", $use, ";")] )?
444            ///
445            #[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            /// ```
449            #[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    /// Returns `true` if the inner value is default.
466    /// ```
467    /// use is_default::IsDefault;
468    /// use std::borrow::Cow;
469    ///
470    /// assert!(Cow::from("").is_default());
471    /// assert!(!Cow::from("x").is_default());
472    /// ```
473    #[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            /// Returns `true` if the inner value is default.
486            #[doc = concat!("Always return false if `self.", stringify!($lock), "()` returns an error.")]
487            /// ```
488            /// use is_default::IsDefault;
489            #[doc = concat!("use ", $use, "::", stringify!($t), ";")]
490            ///
491            #[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            /// ```
501            #[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    /// Returns `true` if the inner value is default.
518    /// ```
519    /// use is_default::IsDefault;
520    /// use std::cell::Cell;
521    ///
522    /// assert!(Cell::new(0u8).is_default());
523    /// assert!(!Cell::new(1u8).is_default());
524    /// ```
525    #[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            /// Returns `true` if self is uninitialized.
535            /// ```
536            /// use is_default::IsDefault;
537            #[doc = concat!("use ", $use, "::", stringify!($t), ";")]
538            ///
539            #[doc = concat!("let v = ", stringify!($t), "::<u8>::new();")]
540            /// assert!(v.is_default());
541            /// v.set(0).unwrap();
542            /// assert!(!v.is_default());
543            /// ```
544            #[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    /// Returns `true` if the [`Weak::upgrade`] returns None.
557    /// ```
558    /// use is_default::IsDefault;
559    /// use std::sync::{Arc, Weak};
560    ///
561    /// assert!(Weak::<u8>::new().is_default());
562    /// let x = Arc::new(0u8);
563    /// let xw: Weak<u8> = Arc::downgrade(&x);
564    /// assert!(!xw.is_default());
565    /// drop(x);
566    /// assert!(xw.is_default());
567    /// ```
568    #[inline(always)]
569    fn is_default(&self) -> bool {
570        matches!(self.upgrade(), None)
571    }
572}
573
574impl<T> IsDefault for Cursor<T> {
575    /// Returns `true` if cursor position is `0`.
576    /// ```
577    /// use is_default::IsDefault;
578    /// use std::io::Cursor;
579    ///
580    /// let mut c = Cursor::new([0u8; 1]);
581    /// assert!(c.is_default());
582    /// c.set_position(1);
583    /// assert!(!c.is_default());
584    /// ```
585    #[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    /// Always returns `true` if slice is empty.
596    /// Otherwise, returns `true` if all slice elements is default.
597    /// ```
598    /// use is_default::IsDefault;
599    ///
600    /// assert!(<&[i32]>::default().is_default());
601    /// assert!(&[0].is_default());
602    /// assert!(!&[1].is_default());
603    /// ```
604    #[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    /// Always returns `true` for array [T; 0].
619    /// Otherwise, returns `true` if all array elements is default.
620    /// ```
621    /// use is_default::IsDefault;
622    ///
623    /// assert!([1u8; 0].is_default());
624    /// assert!([0u8].is_default());
625    /// assert!(![1u8].is_default());
626    /// ```
627    #[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    /// Delegates to the implementation of [`IsDefault`] for `T`.
638    ///
639    /// This allows automatically deriving [`IsDefault`] for structs
640    /// that contain `&T` fields.
641    ///
642    /// ```
643    /// # #[cfg(feature = "derive")] {
644    /// use is_default::IsDefault;
645    ///
646    /// #[derive(IsDefault)]
647    /// struct Ref<'a>(&'a u8);
648    ///
649    /// let x = 0u8;
650    /// assert!(Ref(&x).is_default());
651    /// let y = 1u8;
652    /// assert!(!Ref(&y).is_default());
653    /// # }
654    /// ```
655    #[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    /// Delegates to the implementation of [`IsDefault`] for `T`.
666    ///
667    /// This allows automatically deriving [`IsDefault`] for structs
668    /// that contain `&mut T` fields.
669    ///
670    /// ```
671    /// # #[cfg(feature = "derive")] {
672    /// use is_default::IsDefault;
673    ///
674    /// #[derive(IsDefault)]
675    /// struct MutRef<'a>(&'a mut u8);
676    ///
677    /// let mut a = 0u8;
678    /// assert!(MutRef(&mut a).is_default());
679    /// let mut b = 1u8;
680    /// assert!(!MutRef(&mut b).is_default());
681    /// # }
682    /// ```
683    #[inline(always)]
684    fn is_default(&self) -> bool {
685        (**self).is_default()
686    }
687}