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(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
27pub struct Wrapping(u16);
28
29impl Default for Wrapping {
30    fn default() -> Self {
31        Self::nullable()
32    }
33}
34
35impl Wrapping {
36    /// Is the innermost type required?
37    ///
38    /// Examples:
39    ///
40    /// - `String` => false
41    /// - `String!` => true
42    /// - `[String!]` => true
43    /// - `[String]!` => false
44    pub fn inner_is_required(self) -> bool {
45        self.0 & INNER_IS_REQUIRED_FLAG != 0
46    }
47
48    /// Innermost to outermost.
49    pub fn list_wrappings(
50        self,
51    ) -> impl DoubleEndedIterator<Item = ListWrapping> + ExactSizeIterator<Item = ListWrapping> {
52        (0..self.get_list_length()).map(move |i| {
53            if self.0 & (1 << i) == 0 {
54                ListWrapping::NullableList
55            } else {
56                ListWrapping::RequiredList
57            }
58        })
59    }
60
61    fn get_list_length(&self) -> u8 {
62        ((self.0 & LIST_WRAPPER_LENGTH_MASK) >> LIST_WRAPPER_SHIFT) as u8
63    }
64
65    fn set_list_length(&mut self, len: u8) {
66        assert!((len as u32) < MAX_LIST_WRAPINGS, "list wrapper overflow");
67        self.0 = (self.0 & !LIST_WRAPPER_LENGTH_MASK) | ((len as u16) << LIST_WRAPPER_SHIFT);
68    }
69
70    pub fn to_mutable(self) -> MutableWrapping {
71        self.into()
72    }
73
74    pub fn nullable() -> Self {
75        Wrapping(0)
76    }
77
78    pub fn required() -> Self {
79        Wrapping(INNER_IS_REQUIRED_FLAG)
80    }
81
82    #[must_use]
83    pub fn wrap_list(mut self) -> Self {
84        let len = self.get_list_length();
85        self.set_list_length(len + 1);
86        self.0 &= !(1 << len);
87        self
88    }
89
90    #[must_use]
91    pub fn wrap_list_non_null(mut self) -> Self {
92        let len = self.get_list_length();
93        self.set_list_length(len + 1);
94        self.0 |= 1 << len;
95        self
96    }
97
98    #[must_use]
99    pub fn wrap_non_null(mut self) -> Self {
100        let len = self.get_list_length();
101        if len == 0 {
102            self.0 |= INNER_IS_REQUIRED_FLAG;
103        } else {
104            self.0 |= 1 << (len - 1);
105        }
106        self
107    }
108}
109
110#[derive(Clone, Copy, Debug, PartialEq, Eq)]
111pub enum ListWrapping {
112    RequiredList,
113    NullableList,
114}
115
116impl Wrapping {
117    pub fn new(required: bool) -> Self {
118        if required {
119            Self::required()
120        } else {
121            Self::nullable()
122        }
123    }
124
125    pub fn is_nullable(self) -> bool {
126        !self.is_required()
127    }
128
129    pub fn is_required(self) -> bool {
130        self.list_wrappings()
131            .next_back()
132            .map(|lw| matches!(lw, ListWrapping::RequiredList))
133            .unwrap_or(self.inner_is_required())
134    }
135
136    pub fn is_list(self) -> bool {
137        self.list_wrappings().next().is_some()
138    }
139
140    pub fn write_type_string(self, name: &str, mut formatter: &mut dyn std::fmt::Write) -> Result<(), std::fmt::Error> {
141        for _ in 0..self.list_wrappings().len() {
142            write!(formatter, "[")?;
143        }
144
145        write!(formatter, "{name}")?;
146
147        if self.inner_is_required() {
148            write!(formatter, "!")?;
149        }
150
151        for wrapping in self.list_wrappings() {
152            match wrapping {
153                ListWrapping::RequiredList => write!(&mut formatter, "]!")?,
154                ListWrapping::NullableList => write!(&mut formatter, "]")?,
155            };
156        }
157
158        Ok(())
159    }
160}
161
162impl std::fmt::Debug for Wrapping {
163    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164        f.debug_struct("Wrapping")
165            .field("inner_is_required", &self.inner_is_required())
166            .field("list_wrappings", &self.list_wrappings().collect::<Vec<_>>())
167            .finish()
168    }
169}
170
171#[cfg(test)]
172mod tests {
173    use super::*;
174
175    #[test]
176    fn test_wrapping() {
177        let wrapping = Wrapping::required();
178        assert!(wrapping.inner_is_required());
179        assert!(wrapping.is_required() && !wrapping.is_nullable());
180        assert!(!wrapping.is_list());
181        assert_eq!(wrapping.list_wrappings().collect::<Vec<_>>(), vec![]);
182
183        let mut wrapping = Wrapping::nullable();
184        assert!(!wrapping.inner_is_required());
185        assert!(wrapping.is_nullable() && !wrapping.is_required());
186        assert!(!wrapping.is_list());
187        assert_eq!(wrapping.list_wrappings().collect::<Vec<_>>(), vec![]);
188
189        wrapping = wrapping.wrap_list();
190        assert!(!wrapping.inner_is_required());
191        assert!(wrapping.is_nullable() && !wrapping.is_required());
192        assert!(wrapping.is_list());
193        assert_eq!(
194            wrapping.list_wrappings().collect::<Vec<_>>(),
195            vec![ListWrapping::NullableList]
196        );
197
198        wrapping = wrapping.wrap_list_non_null();
199        assert!(!wrapping.inner_is_required());
200        assert!(wrapping.is_required() && !wrapping.is_nullable());
201        assert!(wrapping.is_list());
202        assert_eq!(
203            wrapping.list_wrappings().collect::<Vec<_>>(),
204            vec![ListWrapping::NullableList, ListWrapping::RequiredList]
205        );
206
207        wrapping = wrapping.wrap_list();
208        assert!(!wrapping.inner_is_required());
209        assert!(wrapping.is_nullable() && !wrapping.is_required());
210        assert!(wrapping.is_list());
211        assert_eq!(
212            wrapping.list_wrappings().collect::<Vec<_>>(),
213            vec![
214                ListWrapping::NullableList,
215                ListWrapping::RequiredList,
216                ListWrapping::NullableList
217            ]
218        );
219    }
220
221    #[test]
222    fn test_mutable_wrapping() {
223        let mut wrapping = Wrapping::default()
224            .wrap_non_null()
225            .wrap_list()
226            .wrap_list_non_null()
227            .wrap_list()
228            .to_mutable();
229
230        assert!(wrapping.is_nullable());
231        assert_eq!(wrapping.pop_outermost_list_wrapping(), Some(ListWrapping::NullableList));
232
233        assert!(wrapping.is_required());
234        assert_eq!(wrapping.pop_outermost_list_wrapping(), Some(ListWrapping::RequiredList));
235
236        assert!(wrapping.is_nullable());
237        assert_eq!(wrapping.pop_outermost_list_wrapping(), Some(ListWrapping::NullableList));
238
239        assert!(wrapping.is_required());
240        assert_eq!(wrapping.pop_outermost_list_wrapping(), None);
241
242        let mut wrapping = Wrapping::default().wrap_list().wrap_list_non_null().to_mutable();
243
244        assert!(wrapping.is_required());
245        assert_eq!(wrapping.pop_outermost_list_wrapping(), Some(ListWrapping::RequiredList));
246
247        assert!(wrapping.is_nullable());
248        assert_eq!(wrapping.pop_outermost_list_wrapping(), Some(ListWrapping::NullableList));
249
250        assert!(wrapping.is_nullable());
251        assert_eq!(wrapping.pop_outermost_list_wrapping(), None);
252    }
253
254    #[test]
255    fn test_wrapping_order() {
256        let wrapping = Wrapping::default()
257            .wrap_non_null()
258            .wrap_list()
259            .wrap_list()
260            .wrap_list_non_null()
261            .wrap_list();
262        assert!(wrapping.inner_is_required());
263        assert_eq!(
264            wrapping.list_wrappings().collect::<Vec<_>>(),
265            vec![
266                ListWrapping::NullableList,
267                ListWrapping::NullableList,
268                ListWrapping::RequiredList,
269                ListWrapping::NullableList
270            ]
271        );
272
273        let wrapping = Wrapping::required()
274            .wrap_list()
275            .wrap_list()
276            .wrap_list_non_null()
277            .wrap_list()
278            .wrap_non_null();
279        assert!(wrapping.inner_is_required());
280        assert_eq!(
281            wrapping.list_wrappings().collect::<Vec<_>>(),
282            vec![
283                ListWrapping::NullableList,
284                ListWrapping::NullableList,
285                ListWrapping::RequiredList,
286                ListWrapping::RequiredList
287            ]
288        );
289
290        let mut wrapping = Wrapping::required()
291            .wrap_list()
292            .wrap_list()
293            .wrap_list_non_null()
294            .wrap_list()
295            .to_mutable();
296        assert_eq!(wrapping.pop_outermost_list_wrapping(), Some(ListWrapping::NullableList));
297        assert_eq!(wrapping.pop_outermost_list_wrapping(), Some(ListWrapping::RequiredList));
298        assert_eq!(wrapping.pop_outermost_list_wrapping(), Some(ListWrapping::NullableList));
299        assert_eq!(wrapping.pop_outermost_list_wrapping(), Some(ListWrapping::NullableList));
300    }
301
302    #[test]
303    fn back_and_forth() {
304        let original = Wrapping::required().wrap_list_non_null();
305        let mut wrapping = original.to_mutable();
306        let list_wrapping = wrapping.pop_outermost_list_wrapping().unwrap();
307        wrapping.push_outermost_list_wrapping(list_wrapping);
308        assert_eq!(Wrapping::from(wrapping), original);
309
310        let original = Wrapping::nullable().wrap_list();
311        let mut wrapping = original.to_mutable();
312        let list_wrapping = wrapping.pop_outermost_list_wrapping().unwrap();
313        wrapping.push_outermost_list_wrapping(list_wrapping);
314        assert_eq!(Wrapping::from(wrapping), original);
315    }
316}