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