non_empty_string/trait_impls/
delegated_traits.rs

1//! This module contains traits that are simply delegated to the underlying [`NonEmptyString`].
2//!
3//! The order of traits implemented here follow the same structure as defined in the standard library.
4//! When adding new ones, add them in the same order, so it's easy to keep track.
5//!
6//! The source at the moment of writing is [here](https://github.com/rust-lang/rust/blob/22d41ae90facbffdef9115809e8b6c1f71ebbf7c/library/alloc/src/string.rs#L2019).
7//! The link to master is [here](https://github.com/rust-lang/rust/blob/master/library/alloc/src/string.rs#L2019).
8//!
9
10use crate::NonEmptyString;
11use std::borrow::Cow;
12use std::fmt::Display;
13use std::ops::{self, Add, AddAssign};
14
15#[cfg(not(no_global_oom_handling))]
16impl Extend<char> for NonEmptyString {
17    fn extend<I: IntoIterator<Item = char>>(&mut self, iter: I) {
18        self.0.extend(iter)
19    }
20}
21
22#[cfg(not(no_global_oom_handling))]
23impl<'a> Extend<&'a char> for NonEmptyString {
24    fn extend<I: IntoIterator<Item = &'a char>>(&mut self, iter: I) {
25        self.extend(iter.into_iter().cloned());
26    }
27}
28
29#[cfg(not(no_global_oom_handling))]
30impl<'a> Extend<&'a str> for NonEmptyString {
31    fn extend<I: IntoIterator<Item = &'a str>>(&mut self, iter: I) {
32        iter.into_iter().for_each(move |s| self.push_str(s));
33    }
34}
35
36#[cfg(not(no_global_oom_handling))]
37impl Extend<Box<str>> for NonEmptyString {
38    fn extend<I: IntoIterator<Item = Box<str>>>(&mut self, iter: I) {
39        iter.into_iter().for_each(move |s| self.push_str(&s));
40    }
41}
42
43#[cfg(not(no_global_oom_handling))]
44impl Extend<String> for NonEmptyString {
45    fn extend<I: IntoIterator<Item = String>>(&mut self, iter: I) {
46        iter.into_iter().for_each(move |s| self.0.push_str(&s));
47    }
48}
49
50#[cfg(not(no_global_oom_handling))]
51impl<'a> Extend<Cow<'a, str>> for NonEmptyString {
52    fn extend<I: IntoIterator<Item = Cow<'a, str>>>(&mut self, iter: I) {
53        iter.into_iter().for_each(move |s| self.push_str(&s));
54    }
55}
56
57macro_rules! impl_eq {
58    ($lhs:ty, $rhs: ty) => {
59        #[allow(unused_lifetimes)]
60        impl<'a, 'b> PartialEq<$rhs> for $lhs {
61            #[inline]
62            fn eq(&self, other: &$rhs) -> bool {
63                PartialEq::eq(&self[..], &other[..])
64            }
65        }
66
67        #[allow(unused_lifetimes)]
68        impl<'a, 'b> PartialEq<$lhs> for $rhs {
69            #[inline]
70            fn eq(&self, other: &$lhs) -> bool {
71                PartialEq::eq(&self[..], &other[..])
72            }
73        }
74    };
75}
76
77impl_eq! { NonEmptyString, str }
78impl_eq! { NonEmptyString, &'a str }
79#[cfg(not(no_global_oom_handling))]
80impl_eq! { Cow<'a, str>, NonEmptyString }
81#[cfg(not(no_global_oom_handling))]
82impl_eq! { String, NonEmptyString }
83
84// No sensible implementation for Default
85// impl Default for NonEmptyString {
86// }
87
88impl Display for NonEmptyString {
89    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90        Display::fmt(&self.0, f)
91    }
92}
93
94// Derived:
95// impl fmt::Debug for String {
96// }
97
98// Derived:
99// impl hash::Hash for NonEmptyString {
100// }
101
102#[cfg(not(no_global_oom_handling))]
103impl Add<&str> for NonEmptyString {
104    type Output = NonEmptyString;
105
106    #[inline]
107    fn add(mut self, other: &str) -> NonEmptyString {
108        self.push_str(other);
109        self
110    }
111}
112
113#[cfg(not(no_global_oom_handling))]
114impl AddAssign<&str> for NonEmptyString {
115    #[inline]
116    fn add_assign(&mut self, other: &str) {
117        self.push_str(other);
118    }
119}
120
121macro_rules! index_impl {
122    ($t:ty) => {
123        impl ops::Index<$t> for NonEmptyString {
124            type Output = str;
125
126            #[inline]
127            fn index(&self, index: $t) -> &str {
128                <String as ops::Index<$t>>::index(&self.0, index)
129            }
130        }
131    };
132}
133
134index_impl!(ops::Range<usize>);
135index_impl!(ops::RangeTo<usize>);
136index_impl!(ops::RangeFrom<usize>);
137index_impl!(ops::RangeFull);
138index_impl!(ops::RangeInclusive<usize>);
139index_impl!(ops::RangeToInclusive<usize>);
140
141// Not 100% sure if index_mut allows turning a NonEmptyString into an empty string or not, let's leave it out until sure.
142// macro_rules! index_mut_impl {
143//     ($t:ty) => {
144//         impl ops::IndexMut<$t> for NonEmptyString {
145//             #[inline]
146//             fn index_mut(&mut self, index: $t) -> &mut str {
147//                 <String as ops::IndexMut<$t>>::index_mut(&mut self.0, index)
148//             }
149//         }
150//     };
151// }
152
153// index_mut_impl!(ops::Range<usize>);
154// index_mut_impl!(ops::RangeTo<usize>);
155// index_mut_impl!(ops::RangeFrom<usize>);
156// index_mut_impl!(ops::RangeFull);
157// index_mut_impl!(ops::RangeInclusive<usize>);
158// index_mut_impl!(ops::RangeToInclusive<usize>);
159
160// Point of discussion, see https://github.com/MidasLamb/non-empty-string/pull/11
161// impl ops::Deref for NonEmptyString {
162// }
163
164// This would mean people could empty out the string, so no.
165// impl ops::DerefMut for NonEmptyString {
166// }
167
168#[cfg(not(no_global_oom_handling))]
169impl std::fmt::Write for NonEmptyString {
170    #[inline]
171    fn write_str(&mut self, s: &str) -> std::fmt::Result {
172        self.push_str(s);
173        Ok(())
174    }
175
176    #[inline]
177    fn write_char(&mut self, c: char) -> std::fmt::Result {
178        self.push(c);
179        Ok(())
180    }
181}