graphql_wrapping_types/
lib.rs

1mod mutable;
2
3pub use mutable::MutableWrapping;
4
5const LIST_WRAPPER_LENGTH_MASK: u16 = 0b0111_1000_0000_0000;
6const LIST_WRAPPER_SHIFT: u32 = LIST_WRAPPER_LENGTH_MASK.trailing_zeros();
7const LIST_WRAPPER_MASK: u16 = 0b0000_0111_1111_1111;
8const MAX_LIST_WRAPINGS: u32 = LIST_WRAPPER_MASK.trailing_ones();
9const INNER_IS_REQUIRED_FLAG: u16 = 0b1000_0000_0000_0000;
10
11/// It's structured as follows:
12///
13///```text
14///      list wrapper length (4 bits)
15//       |
16///      ↓     ↓ list_wrapping (1 == Required / 0 == Nullable)
17///   ┌───┐┌───────────┐
18///  0000_0000_0000_0000
19///  ↑
20///  inner_is_required flag (1 == required)
21///```
22///
23/// The list_wrapping is stored from innermost to outermost and use the start and end
24/// as the positions within the list_wrapping bits. Acting like a simplified fixed capacity VecDeque.
25/// For simplicity of bit shifts the list wrapping is stored from right to left.
26#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize)]
27pub struct Wrapping(u16);
28
29impl Wrapping {
30    /// Is the innermost type required?
31    ///
32    /// Examples:
33    ///
34    /// - `String` => false
35    /// - `String!` => true
36    /// - `[String!]` => true
37    /// - `[String]!` => false
38    pub fn inner_is_required(self) -> bool {
39        self.0 & INNER_IS_REQUIRED_FLAG != 0
40    }
41
42    /// Innermost to outermost.
43    pub fn list_wrappings(
44        self,
45    ) -> impl DoubleEndedIterator<Item = ListWrapping> + ExactSizeIterator<Item = ListWrapping> {
46        (0..self.get_list_length()).map(move |i| {
47            if self.0 & (1 << i) == 0 {
48                ListWrapping::List
49            } else {
50                ListWrapping::ListNonNull
51            }
52        })
53    }
54
55    /// From innermost to outermost.
56    pub fn iter(self) -> impl Iterator<Item = WrappingType> {
57        [self.inner_is_required().then_some(WrappingType::NonNull)]
58            .into_iter()
59            .chain(self.list_wrappings().flat_map(|lw| match lw {
60                ListWrapping::List => [Some(WrappingType::List), None],
61                ListWrapping::ListNonNull => [Some(WrappingType::List), Some(WrappingType::NonNull)],
62            }))
63            .flatten()
64    }
65
66    const fn get_list_length(&self) -> u8 {
67        ((self.0 & LIST_WRAPPER_LENGTH_MASK) >> LIST_WRAPPER_SHIFT) as u8
68    }
69
70    const fn set_list_length(&mut self, len: u8) {
71        assert!((len as u32) < MAX_LIST_WRAPINGS, "list wrapper overflow");
72        self.0 = (self.0 & INNER_IS_REQUIRED_FLAG) | ((len as u16) << LIST_WRAPPER_SHIFT) | (self.0 & ((1 << len) - 1));
73    }
74
75    pub fn to_mutable(self) -> MutableWrapping {
76        self.into()
77    }
78
79    #[must_use]
80    pub const fn list(mut self) -> Self {
81        let len = self.get_list_length();
82        self.set_list_length(len + 1);
83        self.0 &= !(1 << len);
84        self
85    }
86
87    #[must_use]
88    pub const fn list_non_null(mut self) -> Self {
89        let len = self.get_list_length();
90        self.set_list_length(len + 1);
91        self.0 |= 1 << len;
92        self
93    }
94
95    #[must_use]
96    pub const fn non_null(mut self) -> Self {
97        let len = self.get_list_length();
98        if len == 0 {
99            self.0 |= INNER_IS_REQUIRED_FLAG;
100        } else {
101            self.0 |= 1 << (len - 1);
102        }
103        self
104    }
105
106    /// Whether a type wrapped with Self could receive a type wrapping with other.
107    pub fn is_equal_or_more_lenient_than(self, other: Wrapping) -> bool {
108        if self.inner_is_required() && !other.inner_is_required() {
109            return false;
110        }
111        if self.get_list_length() != other.get_list_length() {
112            return false;
113        }
114        for (s, o) in self.list_wrappings().zip(other.list_wrappings()) {
115            if s == ListWrapping::ListNonNull && o == ListWrapping::List {
116                return false;
117            }
118        }
119        true
120    }
121
122    pub fn without_list(self) -> Option<Wrapping> {
123        let mut wrapping = self.to_mutable();
124        wrapping.pop_outermost_list_wrapping().map(|_| wrapping.into())
125    }
126
127    pub fn without_non_null(mut self) -> Wrapping {
128        if self.is_nullable() {
129            self
130        } else if self.is_list() {
131            let mut wrapping = self.to_mutable();
132            wrapping.pop_outermost_list_wrapping();
133            wrapping.push_outermost_list_wrapping(ListWrapping::List);
134            wrapping.into()
135        } else {
136            self.0 &= !INNER_IS_REQUIRED_FLAG;
137            self
138        }
139    }
140}
141
142#[derive(Clone, Copy, Debug, PartialEq, Eq)]
143pub enum WrappingType {
144    NonNull,
145    List,
146}
147
148#[derive(Clone, Copy, Debug, PartialEq, Eq)]
149pub enum ListWrapping {
150    ListNonNull,
151    List,
152}
153
154impl Wrapping {
155    pub fn is_nullable(self) -> bool {
156        !self.is_non_null()
157    }
158
159    pub fn is_non_null(self) -> bool {
160        self.list_wrappings()
161            .next_back()
162            .map(|lw| matches!(lw, ListWrapping::ListNonNull))
163            .unwrap_or(self.inner_is_required())
164    }
165
166    pub fn is_list(self) -> bool {
167        self.list_wrappings().next().is_some()
168    }
169
170    pub fn type_display(self, name: &str) -> impl std::fmt::Display {
171        WrappingDisplay { name, wrapping: self }
172    }
173}
174
175struct WrappingDisplay<'a> {
176    name: &'a str,
177    wrapping: Wrapping,
178}
179
180impl std::fmt::Display for WrappingDisplay<'_> {
181    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
182        for _ in 0..self.wrapping.get_list_length() {
183            write!(f, "[")?;
184        }
185
186        write!(f, "{}", self.name)?;
187
188        if self.wrapping.inner_is_required() {
189            write!(f, "!")?;
190        }
191
192        for wrapping in self.wrapping.list_wrappings() {
193            match wrapping {
194                ListWrapping::ListNonNull => write!(f, "]!")?,
195                ListWrapping::List => write!(f, "]")?,
196            };
197        }
198
199        Ok(())
200    }
201}
202
203impl std::fmt::Debug for Wrapping {
204    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
205        f.debug_struct("Wrapping")
206            .field("inner_is_required", &self.inner_is_required())
207            .field("list_wrappings", &self.list_wrappings().collect::<Vec<_>>())
208            .field("binary", &format!("{:016b}", self.0))
209            .finish()
210    }
211}
212
213#[cfg(test)]
214mod tests {
215    use super::*;
216
217    #[test]
218    fn test_wrapping() {
219        let wrapping = Wrapping::default().non_null();
220        assert!(wrapping.inner_is_required());
221        assert!(wrapping.is_non_null() && !wrapping.is_nullable());
222        assert!(!wrapping.is_list());
223        assert_eq!(wrapping.list_wrappings().collect::<Vec<_>>(), vec![]);
224
225        let mut wrapping = Wrapping::default();
226        assert!(!wrapping.inner_is_required());
227        assert!(wrapping.is_nullable() && !wrapping.is_non_null());
228        assert!(!wrapping.is_list());
229        assert_eq!(wrapping.list_wrappings().collect::<Vec<_>>(), vec![]);
230
231        wrapping = wrapping.list();
232        assert!(!wrapping.inner_is_required());
233        assert!(wrapping.is_nullable() && !wrapping.is_non_null());
234        assert!(wrapping.is_list());
235        assert_eq!(wrapping.list_wrappings().collect::<Vec<_>>(), vec![ListWrapping::List]);
236
237        wrapping = wrapping.list_non_null();
238        assert!(!wrapping.inner_is_required());
239        assert!(wrapping.is_non_null() && !wrapping.is_nullable());
240        assert!(wrapping.is_list());
241        assert_eq!(
242            wrapping.list_wrappings().collect::<Vec<_>>(),
243            vec![ListWrapping::List, ListWrapping::ListNonNull]
244        );
245
246        wrapping = wrapping.list();
247        assert!(!wrapping.inner_is_required());
248        assert!(wrapping.is_nullable() && !wrapping.is_non_null());
249        assert!(wrapping.is_list());
250        assert_eq!(
251            wrapping.list_wrappings().collect::<Vec<_>>(),
252            vec![ListWrapping::List, ListWrapping::ListNonNull, ListWrapping::List]
253        );
254    }
255
256    #[test]
257    fn test_mutable_wrapping() {
258        let mut wrapping = Wrapping::default()
259            .non_null()
260            .list()
261            .list_non_null()
262            .list()
263            .to_mutable();
264
265        assert!(wrapping.is_nullable());
266        assert_eq!(wrapping.pop_outermost_list_wrapping(), Some(ListWrapping::List));
267
268        assert!(wrapping.is_required());
269        assert_eq!(wrapping.pop_outermost_list_wrapping(), Some(ListWrapping::ListNonNull));
270
271        assert!(wrapping.is_nullable());
272        assert_eq!(wrapping.pop_outermost_list_wrapping(), Some(ListWrapping::List));
273
274        assert!(wrapping.is_required());
275        assert_eq!(wrapping.pop_outermost_list_wrapping(), None);
276
277        let mut wrapping = Wrapping::default().list().list_non_null().to_mutable();
278
279        assert!(wrapping.is_required());
280        assert_eq!(wrapping.pop_outermost_list_wrapping(), Some(ListWrapping::ListNonNull));
281
282        assert!(wrapping.is_nullable());
283        assert_eq!(wrapping.pop_outermost_list_wrapping(), Some(ListWrapping::List));
284
285        assert!(wrapping.is_nullable());
286        assert_eq!(wrapping.pop_outermost_list_wrapping(), None);
287    }
288
289    #[test]
290    fn test_wrapping_order() {
291        let wrapping = Wrapping::default().non_null().list().list().list_non_null().list();
292        assert!(wrapping.inner_is_required());
293        assert_eq!(
294            wrapping.list_wrappings().collect::<Vec<_>>(),
295            vec![
296                ListWrapping::List,
297                ListWrapping::List,
298                ListWrapping::ListNonNull,
299                ListWrapping::List
300            ]
301        );
302
303        let wrapping = Wrapping::default()
304            .non_null()
305            .list()
306            .list()
307            .list_non_null()
308            .list()
309            .non_null();
310        assert!(wrapping.inner_is_required());
311        assert_eq!(
312            wrapping.list_wrappings().collect::<Vec<_>>(),
313            vec![
314                ListWrapping::List,
315                ListWrapping::List,
316                ListWrapping::ListNonNull,
317                ListWrapping::ListNonNull
318            ]
319        );
320
321        let mut wrapping = Wrapping::default()
322            .non_null()
323            .list()
324            .list()
325            .list_non_null()
326            .list()
327            .to_mutable();
328        assert_eq!(wrapping.pop_outermost_list_wrapping(), Some(ListWrapping::List));
329        assert_eq!(wrapping.pop_outermost_list_wrapping(), Some(ListWrapping::ListNonNull));
330        assert_eq!(wrapping.pop_outermost_list_wrapping(), Some(ListWrapping::List));
331        assert_eq!(wrapping.pop_outermost_list_wrapping(), Some(ListWrapping::List));
332    }
333
334    #[test]
335    fn back_and_forth() {
336        let original = Wrapping::default().non_null().list_non_null();
337        let mut wrapping = original.to_mutable();
338        let list_wrapping = wrapping.pop_outermost_list_wrapping().unwrap();
339        assert_eq!(Wrapping::from(wrapping.clone()), Wrapping::default().non_null());
340
341        wrapping.push_outermost_list_wrapping(list_wrapping);
342        assert_eq!(Wrapping::from(wrapping), original);
343
344        let original = Wrapping::default().list();
345        let mut wrapping = original.to_mutable();
346        let list_wrapping = wrapping.pop_outermost_list_wrapping().unwrap();
347        assert_eq!(Wrapping::from(wrapping.clone()), Wrapping::default());
348
349        wrapping.push_outermost_list_wrapping(list_wrapping);
350        assert_eq!(Wrapping::from(wrapping), original);
351    }
352
353    #[test]
354    fn test_is_equal_or_more_lenient_than() {
355        let non_null_list = Wrapping::default().non_null().list();
356        let non_null_list_non_null = Wrapping::default().non_null().list_non_null();
357        assert!(non_null_list.is_equal_or_more_lenient_than(non_null_list_non_null));
358        assert!(!non_null_list_non_null.is_equal_or_more_lenient_than(non_null_list));
359
360        let list = Wrapping::default().list();
361        assert!(list.is_equal_or_more_lenient_than(non_null_list));
362        assert!(!non_null_list.is_equal_or_more_lenient_than(list));
363
364        let list_non_null = Wrapping::default().list_non_null();
365        assert!(!non_null_list.is_equal_or_more_lenient_than(list_non_null));
366        assert!(!list_non_null.is_equal_or_more_lenient_than(non_null_list));
367    }
368}