kutil_std/foster/
string_vector.rs

1use super::{
2    super::{borrow::*, iter::*},
3    foster::*,
4    has_length::*,
5    iterator::*,
6};
7
8use std::{cmp::*, hash::*, slice::*};
9
10/// [Foster] for [Vec]\<[String]\>.
11///
12/// Supports [IntoOwned], [HasLength], [Eq]/[PartialEq], [Ord]/[PartialOrd], [Hash], and
13/// [IntoIterator].
14pub type FosterStringVector = Foster<Vec<String>, &'static [&'static str]>;
15
16impl IntoOwned for FosterStringVector {
17    fn into_owned(self) -> Self {
18        match self {
19            Self::Owned(_) => self,
20            Self::Fostered(strings) => Self::new_owned(strings.iter().map(|string| (*string).into()).collect()),
21        }
22    }
23}
24
25impl HasLength for FosterStringVector {
26    fn len(&self) -> usize {
27        match self {
28            Self::Owned(strings) => strings.len(),
29            Self::Fostered(strings) => strings.len(),
30        }
31    }
32}
33
34impl PartialEq for FosterStringVector {
35    fn eq(&self, other: &Self) -> bool {
36        match self {
37            Self::Owned(strings) => match other {
38                Self::Owned(other_strings) => strings.eq(other_strings),
39
40                Self::Fostered(other_strings) => {
41                    if strings.len() == other_strings.len() {
42                        let mut equal = true;
43                        for (index, string) in strings.iter().enumerate() {
44                            if string.ne(other_strings[index]) {
45                                equal = false;
46                                break;
47                            }
48                        }
49                        equal
50                    } else {
51                        false
52                    }
53                }
54            },
55
56            Self::Fostered(strings) => match other {
57                Self::Owned(other_strings) => {
58                    if strings.len() == other_strings.len() {
59                        let mut equal = true;
60                        for (index, string) in strings.iter().enumerate() {
61                            if string.ne(&other_strings[index]) {
62                                equal = false;
63                                break;
64                            }
65                        }
66                        equal
67                    } else {
68                        false
69                    }
70                }
71
72                Self::Fostered(other_strings) => strings.eq(other_strings),
73            },
74        }
75    }
76}
77
78impl Eq for FosterStringVector {}
79
80impl PartialOrd for FosterStringVector {
81    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
82        // See: core::slice::cmp::SlicePartialOrd
83
84        match self {
85            Self::Owned(strings) => match other {
86                Self::Owned(other_strings) => strings.partial_cmp(other_strings),
87
88                Self::Fostered(other_strings) => {
89                    let strings_length = strings.len();
90                    let other_strings_length = other_strings.len();
91                    let length = min(strings_length, other_strings_length);
92
93                    // enable compiler bound check elimination
94                    let strings_bounded = &strings[..length];
95                    let other_strings_bounded = &other_strings[..length];
96
97                    for index in 0..length {
98                        match strings_bounded[index].as_str().partial_cmp(other_strings_bounded[index]) {
99                            Some(Ordering::Equal) => (),
100                            not_equal => return not_equal,
101                        }
102                    }
103
104                    strings_length.partial_cmp(&other_strings_length)
105                }
106            },
107
108            Self::Fostered(strings) => match other {
109                Self::Owned(other_strings) => {
110                    let strings_length = strings.len();
111                    let other_strings_length = other_strings.len();
112                    let length = min(strings_length, other_strings_length);
113
114                    // enable compiler bound check elimination
115                    let strings_bounded = &strings[..length];
116                    let other_strings_bounded = &other_strings[..length];
117
118                    for index in 0..length {
119                        match strings_bounded[index].partial_cmp(other_strings_bounded[index].as_str()) {
120                            Some(Ordering::Equal) => (),
121                            not_equal => return not_equal,
122                        }
123                    }
124
125                    strings_length.partial_cmp(&other_strings_length)
126                }
127
128                Self::Fostered(other_strings) => strings.partial_cmp(other_strings),
129            },
130        }
131    }
132}
133
134impl Ord for FosterStringVector {
135    fn cmp(&self, other: &Self) -> Ordering {
136        // See: core::slice::cmp::SliceOrd
137
138        match self {
139            Self::Owned(strings) => match other {
140                Self::Owned(other_strings) => strings.cmp(other_strings),
141
142                Self::Fostered(other_strings) => {
143                    let strings_length = strings.len();
144                    let other_strings_length = other_strings.len();
145                    let length = min(strings_length, other_strings_length);
146
147                    // enable compiler bound check elimination
148                    let strings_bounded = &strings[..length];
149                    let other_strings_bounded = &other_strings[..length];
150
151                    for index in 0..length {
152                        match strings_bounded[index].as_str().cmp(other_strings_bounded[index]) {
153                            Ordering::Equal => (),
154                            not_equal => return not_equal,
155                        }
156                    }
157
158                    strings_length.cmp(&other_strings_length)
159                }
160            },
161
162            Self::Fostered(strings) => match other {
163                Self::Owned(other_strings) => {
164                    let strings_length = strings.len();
165                    let other_strings_length = other_strings.len();
166                    let length = min(strings_length, other_strings_length);
167
168                    // enable compiler bound check elimination
169                    let strings_bounded = &strings[..length];
170                    let other_strings_bounded = &other_strings[..length];
171
172                    for index in 0..length {
173                        match strings_bounded[index].cmp(other_strings_bounded[index].as_str()) {
174                            Ordering::Equal => (),
175                            not_equal => return not_equal,
176                        }
177                    }
178
179                    strings_length.cmp(&other_strings_length)
180                }
181
182                Self::Fostered(other_strings) => strings.cmp(other_strings),
183            },
184        }
185    }
186}
187
188impl Hash for FosterStringVector {
189    fn hash<HasherT>(&self, state: &mut HasherT)
190    where
191        HasherT: Hasher,
192    {
193        match self {
194            Self::Owned(strings) => {
195                for string in strings {
196                    state.write(string.as_bytes());
197                }
198            }
199
200            Self::Fostered(strings) => {
201                for string in strings.iter() {
202                    state.write(string.as_bytes());
203                }
204            }
205        }
206    }
207}
208
209impl<'own> IntoIterator for &'own FosterStringVector {
210    type Item = &'own str;
211    type IntoIter =
212        FosterIterator<&'own str, &'own String, &'own &'static str, Iter<'own, String>, Iter<'own, &'static str>>;
213
214    fn into_iter(self) -> Self::IntoIter {
215        match self {
216            Foster::Owned(strings) => Foster::new_owned(ConvertingIterator::new(strings.iter(), |string| &string)),
217            Foster::Fostered(strings) => Foster::new_fostered(ConvertingIterator::new(strings.iter(), |string| string)),
218        }
219    }
220}
221
222/// Delegates traits to a [FosterStringVector] newtype.
223///
224/// Example:
225///
226/// ```
227/// #[derive(Clone, Debug)]
228/// pub struct MyType(FosterStringVector);
229///
230/// delegate_newtype_of_foster_string_vector!(MyType);
231/// ```
232///
233#[macro_export]
234macro_rules! delegate_newtype_of_foster_string_vector {
235    ( $type:ty ) => {
236        impl $type {
237            /// Constructor.
238            pub fn new_owned(strings: ::std::vec::Vec<::std::string::String>) -> Self {
239                Self(::kutil_std::foster::Foster::new_owned(strings))
240            }
241
242            /// Constructor.
243            pub const fn new_fostered(strings: &'static [&'static str]) -> Self {
244                Self(::kutil_std::foster::Foster::new_fostered(strings))
245            }
246        }
247
248        impl ::kutil_std::borrow::IntoOwned for $type {
249            fn into_owned(self) -> Self {
250                match self.0 {
251                    ::kutil_std::foster::Foster::Owned(_) => self,
252                    ::kutil_std::foster::Foster::Fostered(_) => Self(self.0.into_owned()),
253                }
254            }
255        }
256
257        impl ::kutil_std::foster::HasLength for $type {
258            fn len(&self) -> usize {
259                self.0.len()
260            }
261        }
262
263        impl ::std::convert::From<::std::vec::Vec<::std::string::String>> for $type {
264            fn from(strings: Vec<::std::string::String>) -> Self {
265                strings.into()
266            }
267        }
268
269        impl ::std::cmp::PartialEq for $type {
270            fn eq(&self, other: &Self) -> bool {
271                self.0.eq(&other.0)
272            }
273        }
274
275        impl ::std::cmp::Eq for $type {}
276
277        impl ::std::cmp::PartialOrd for $type {
278            fn partial_cmp(&self, other: &Self) -> ::std::option::Option<::std::cmp::Ordering> {
279                self.0.partial_cmp(&other.0)
280            }
281        }
282
283        impl ::std::cmp::Ord for $type {
284            fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
285                self.0.cmp(&other.0)
286            }
287        }
288
289        impl ::std::hash::Hash for $type {
290            fn hash<HasherT>(&self, state: &mut HasherT)
291            where
292                HasherT: ::std::hash::Hasher,
293            {
294                self.0.hash(state)
295            }
296        }
297
298        impl<'own> ::std::iter::IntoIterator for &'own $type {
299            type Item = &'own str;
300            type IntoIter = ::kutil_std::foster::FosterIterator<
301                &'own str,
302                &'own ::std::string::String,
303                &'own &'static str,
304                ::std::slice::Iter<'own, ::std::string::String>,
305                ::std::slice::Iter<'own, &'static str>,
306            >;
307
308            fn into_iter(self) -> Self::IntoIter {
309                self.0.into_iter()
310            }
311        }
312    };
313}