graphql_wrapping_types/
lib.rs1mod 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#[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 pub fn inner_is_required(self) -> bool {
45 self.0 & INNER_IS_REQUIRED_FLAG != 0
46 }
47
48 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 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}