1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//! Traits and functions for determining if some collection is empty.

/// Useful functions exported by `tool::empty`.
pub mod prelude {
    #[doc(inline)]
    pub use super::{empty, non_empty};
}

/// Things that can be "empty".
pub trait IsEmpty {
    fn is_empty(&self) -> bool;
}

/// True if the value is "empty"
///
/// For example: `[]`, `""`, `Some([])`, `None::<T: Empty>`, etc...
pub fn empty<T: ?Sized + IsEmpty>(value: &T) -> bool {
    value.is_empty()
}

/// False if the value is "empty"
///
/// Shortcut for `|x|{ !empty(x) }`.
///
/// Example:
///
/// ```rust
/// use tool::non_empty;
/// let strings: Vec<_> = vec!["my string", "", "asdf", ""]
///     .into_iter()
///     .filter(non_empty)
///     .collect();
/// assert_eq!(strings, vec!["my string", "asdf"]);
/// ```
pub fn non_empty<T: ?Sized + IsEmpty>(value: &T) -> bool {
    !value.is_empty()
}

impl<'a, T: IsEmpty + ?Sized> IsEmpty for &'a T {
    fn is_empty(&self) -> bool {
        (**self).is_empty()
    }
}

impl<'a, T: IsEmpty + ?Sized> IsEmpty for &'a mut T {
    fn is_empty(&self) -> bool {
        (**self).is_empty()
    }
}

impl<T: IsEmpty> IsEmpty for Option<T> {
    fn is_empty(&self) -> bool {
        self.as_ref().map(|x| x.is_empty()).unwrap_or(true)
    }
}

impl IsEmpty for str {
    fn is_empty(&self) -> bool {
        self.is_empty()
    }
}

impl<T> IsEmpty for [T] {
    fn is_empty(&self) -> bool {
        self.is_empty()
    }
}

if_std! {
    use std::prelude::v1::*;
    use std::ffi::{OsStr, OsString, CString, CStr};
    use std::collections::{HashMap, BTreeMap};
    use core::hash::{Hash, BuildHasher};
    use std::rc::Rc;
    use std::sync::Arc;

    impl<K, V, S> IsEmpty for HashMap<K, V, S>
        where K: Eq + Hash,
              S: BuildHasher,
    {
        fn is_empty(&self) -> bool {
            HashMap::is_empty(self)
        }
    }

    impl<K, V> IsEmpty for BTreeMap<K, V> {
        fn is_empty(&self) -> bool {
            BTreeMap::is_empty(self)
        }
    }

    impl<T> IsEmpty for Vec<T> {
        fn is_empty(&self) -> bool {
            Vec::is_empty(self)
        }
    }

    impl IsEmpty for String {
        fn is_empty(&self) -> bool {
            str::is_empty(self)
        }
    }

    impl IsEmpty for OsStr {
        fn is_empty(&self) -> bool {
            OsStr::is_empty(self)
        }
    }

    impl IsEmpty for OsString {
        fn is_empty(&self) -> bool {
            OsStr::is_empty(self)
        }
    }

    impl IsEmpty for CStr {
        fn is_empty(&self) -> bool {
            unsafe {
                *self.as_ptr() == 0
            }
        }
    }

    impl IsEmpty for CString {
        fn is_empty(&self) -> bool {
            (&**self).is_empty()
        }
    }

    impl<T: ?Sized + IsEmpty> IsEmpty for Box<T> {
        fn is_empty(&self) -> bool {
            (&**self).is_empty()
        }
    }

    impl<T: ?Sized + IsEmpty> IsEmpty for Rc<T> {
        fn is_empty(&self) -> bool {
            (&**self).is_empty()
        }
    }

    impl<T: ?Sized + IsEmpty> IsEmpty for Arc<T> {
        fn is_empty(&self) -> bool {
            (&**self).is_empty()
        }
    }
}