kutil_std/foster/
byte_string_vector.rs

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