noneifempty/lib.rs
1/*
2 * --------------------
3 * THIS FILE IS LICENSED UNDER THE TERMS OF THE FOLLOWING LICENSE
4 *
5 * this code and any software derived from it may not be used for any purpose. be gay, do crime.
6 *
7 * THE FOLLOWING MESSAGE IS NOT A LICENSE
8 *
9 * <barrow@tilde.team> wrote this file.
10 * by reading this text, you are reading "TRANS RIGHTS".
11 * this file and the content within it is the gay agenda.
12 * if we meet some day, and you think this stuff is worth it,
13 * you can buy me a beer, tea, or something stronger.
14 * -Ezra Barrow
15 * --------------------
16 */
17//! Adds a trait NoneIfEmpty that converts a T to an Option<T> by turning an empty T into None.
18//!
19//! [](https://github.com/barrowsys/noneifempty)
20//! [](https://crates.io/crates/noneifempty/)
21//! [](https://docs.rs/noneifempty)
22//! [](https://www.repostatus.org/#active)
23//!
24//! ```
25//! // Bring the trait into scope
26//! use noneifempty::NoneIfEmpty;
27//!
28//! // Converts empty strings to None
29//! let empty_str = "";
30//! assert_eq!(empty_str.none_if_empty(), None);
31//!
32//! // And full strings to Some
33//! let full_str = "hello, world!";
34//! assert_eq!(full_str.none_if_empty(), Some("hello, world!"));
35//!
36//! // Also works with vecs, hashmaps, hashsets, custom types...
37//! let empty_vec: Vec<&str> = vec![];
38//! let full_vec: Vec<&str> = vec!["hi"];
39//! assert_eq!(empty_vec.none_if_empty(), None);
40//! assert_eq!(full_vec.none_if_empty(), Some(vec!["hi"]));
41//!
42//! // Automatically implemented for Option<T: NoneIfEmpty>
43//! let no_vec: Option<Vec<&str>> = None;
44//! let empty_vec: Option<Vec<&str>> = Some(vec![]);
45//! let full_vec: Option<Vec<&str>> = Some(vec!["hi"]);
46//! assert_eq!(no_vec.none_if_empty(), None);
47//! assert_eq!(empty_vec.none_if_empty(), None);
48//! assert_eq!(full_vec.none_if_empty(), Some(vec!["hi"]));
49//! ```
50
51use std::collections::{HashMap, HashSet};
52
53/// Trait for converting an empty T to None
54pub trait NoneIfEmpty
55where
56 Self: Sized,
57{
58 type Output;
59 fn none_if_empty(self) -> Option<Self::Output>;
60}
61/// Automatically implement NoneIfEmpty for Option<T: NoneIfEmpty>
62///
63/// This is basically a flatten
64impl<N: NoneIfEmpty> NoneIfEmpty for Option<N> {
65 type Output = <N as NoneIfEmpty>::Output;
66 fn none_if_empty(self) -> Option<Self::Output> {
67 (self?).none_if_empty()
68 }
69}
70/// Converts a &str to None if empty
71impl<'s> NoneIfEmpty for &'s str {
72 type Output = &'s str;
73 fn none_if_empty(self) -> Option<&'s str> {
74 if self.is_empty() {
75 None
76 } else {
77 Some(self)
78 }
79 }
80}
81/// Converts a String to None if empty
82impl NoneIfEmpty for String {
83 type Output = String;
84 fn none_if_empty(self) -> Option<String> {
85 if self.is_empty() {
86 None
87 } else {
88 Some(self)
89 }
90 }
91}
92/// Converts a Vec to None if empty
93impl<T> NoneIfEmpty for Vec<T> {
94 type Output = Self;
95 fn none_if_empty(self) -> Option<Self::Output> {
96 if self.is_empty() {
97 None
98 } else {
99 Some(self)
100 }
101 }
102}
103/// Converts a HashMap to None if empty
104impl<K, V> NoneIfEmpty for HashMap<K, V> {
105 type Output = Self;
106 fn none_if_empty(self) -> Option<Self::Output> {
107 if self.is_empty() {
108 None
109 } else {
110 Some(self)
111 }
112 }
113}
114/// Converts a HashSet to None if empty
115impl<T> NoneIfEmpty for HashSet<T> {
116 type Output = Self;
117 fn none_if_empty(self) -> Option<Self::Output> {
118 if self.is_empty() {
119 None
120 } else {
121 Some(self)
122 }
123 }
124}