Skip to main content

jstrict/
kind.rs

1//! JSON value kinds.
2use core::fmt;
3use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign};
4
5/// Value kind.
6///
7/// The six kinds of JSON value. `Kind` values combine with `|` and `&` into a
8/// [`KindSet`], which is how expected-kind errors are reported.
9///
10/// ```
11/// # use jstrict::{Kind, KindSet};
12/// let expected: KindSet = Kind::Number | Kind::String;
13/// assert_eq!(expected.as_disjunction().to_string(), "number or string");
14/// ```
15#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
16pub enum Kind {
17	/// The `null` value.
18	Null,
19
20	/// A boolean, `true` or `false`.
21	Boolean,
22
23	/// A number.
24	Number,
25
26	/// A string.
27	String,
28
29	/// An array.
30	Array,
31
32	/// An object.
33	Object,
34}
35
36impl BitOr for Kind {
37	type Output = KindSet;
38
39	fn bitor(self, other: Self) -> KindSet {
40		KindSet::from(self) | KindSet::from(other)
41	}
42}
43
44impl BitOr<KindSet> for Kind {
45	type Output = KindSet;
46
47	fn bitor(self, other: KindSet) -> KindSet {
48		KindSet::from(self) | other
49	}
50}
51
52impl BitAnd for Kind {
53	type Output = KindSet;
54
55	fn bitand(self, other: Self) -> KindSet {
56		KindSet::from(self) & KindSet::from(other)
57	}
58}
59
60impl BitAnd<KindSet> for Kind {
61	type Output = KindSet;
62
63	fn bitand(self, other: KindSet) -> KindSet {
64		KindSet::from(self) & other
65	}
66}
67
68impl fmt::Display for Kind {
69	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70		match self {
71			Self::Null => write!(f, "null"),
72			Self::Boolean => write!(f, "boolean"),
73			Self::Number => write!(f, "number"),
74			Self::String => write!(f, "string"),
75			Self::Array => write!(f, "array"),
76			Self::Object => write!(f, "object"),
77		}
78	}
79}
80
81macro_rules! kind_set {
82	($($id:ident ($const:ident): $mask:literal),*) => {
83		/// Set of JSON value [`Kind`].
84		#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
85		pub struct KindSet(u8);
86
87		impl KindSet {
88			$(
89				#[doc = concat!("Set containing only [`Kind::", stringify!($id), "`].")]
90				pub const $const: Self = Self($mask);
91			)*
92
93			/// Set containing every [`Kind`].
94			pub const fn all() -> Self {
95				Self($($mask)|*)
96			}
97		}
98
99		impl std::ops::BitOr<Kind> for KindSet {
100			type Output = Self;
101
102			fn bitor(self, other: Kind) -> Self {
103				match other {
104					$(
105						Kind::$id => Self(self.0 | $mask)
106					),*
107				}
108			}
109		}
110
111		impl std::ops::BitOrAssign<Kind> for KindSet {
112			fn bitor_assign(&mut self, other: Kind) {
113				match other {
114					$(
115						Kind::$id => self.0 |= $mask
116					),*
117				}
118			}
119		}
120
121		impl std::ops::BitAnd<Kind> for KindSet {
122			type Output = Self;
123
124			fn bitand(self, other: Kind) -> Self {
125				match other {
126					$(
127						Kind::$id => Self(self.0 & $mask)
128					),*
129				}
130			}
131		}
132
133		impl std::ops::BitAndAssign<Kind> for KindSet {
134			fn bitand_assign(&mut self, other: Kind) {
135				match other {
136					$(
137						Kind::$id => self.0 &= $mask
138					),*
139				}
140			}
141		}
142
143		impl From<Kind> for KindSet {
144			fn from(value: Kind) -> Self {
145				match value {
146					$(
147						Kind::$id => Self($mask)
148					),*
149				}
150			}
151		}
152
153		/// Iterator over the [`Kind`]s of a [`KindSet`], in declaration order.
154		#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
155		pub struct KindSetIter(u8);
156
157		impl Iterator for KindSetIter {
158			type Item = Kind;
159
160			fn size_hint(&self) -> (usize, Option<usize>) {
161				let len = self.0.count_ones() as usize;
162				(len, Some(len))
163			}
164
165			fn next(&mut self) -> Option<Kind> {
166				$(
167					if self.0 & $mask != 0 {
168						self.0 &= !$mask;
169						return Some(Kind::$id)
170					}
171				)*
172
173				None
174			}
175		}
176
177		impl DoubleEndedIterator for KindSetIter {
178			fn next_back(&mut self) -> Option<Kind> {
179				let mut result = None;
180
181				$(
182					if self.0 & $mask != 0 {
183						result = Some((Kind::$id, $mask));
184					}
185				)*
186
187				result.map(|(kind, mask)| {
188					self.0 &= !mask;
189					kind
190				})
191			}
192		}
193
194		impl core::iter::FusedIterator for KindSetIter {}
195		impl core::iter::ExactSizeIterator for KindSetIter {}
196	};
197}
198
199kind_set! {
200	Null (NULL):       0b00_0001,
201	Boolean (BOOLEAN): 0b00_0010,
202	Number (NUMBER):   0b00_0100,
203	String (STRING):   0b00_1000,
204	Array (ARRAY):     0b01_0000,
205	Object (OBJECT):   0b10_0000
206}
207
208impl KindSet {
209	/// The empty set.
210	#[must_use]
211	pub const fn none() -> Self {
212		Self(0)
213	}
214
215	/// Returns the number of kinds in this set.
216	#[must_use]
217	pub const fn len(&self) -> usize {
218		self.0.count_ones() as usize
219	}
220
221	/// Checks if this set is empty.
222	#[must_use]
223	pub const fn is_empty(&self) -> bool {
224		self.0 == 0
225	}
226
227	/// Iterates over the kinds in this set, in declaration order.
228	#[must_use]
229	pub const fn iter(&self) -> KindSetIter {
230		KindSetIter(self.0)
231	}
232
233	/// Displays this set as a disjunction.
234	///
235	/// # Example
236	///
237	/// ```
238	/// # use jstrict::{Kind, KindSet};
239	/// let set = Kind::Null | Kind::String | Kind::Object;
240	/// assert_eq!(set.as_disjunction().to_string(), "null, string or object");
241	/// assert_eq!(KindSet::ARRAY.as_disjunction().to_string(), "array");
242	/// assert_eq!(KindSet::all().as_disjunction().to_string(), "anything");
243	/// assert_eq!(KindSet::none().as_disjunction().to_string(), "nothing");
244	/// ```
245	#[must_use]
246	pub const fn as_disjunction(self) -> KindSetDisjunction {
247		KindSetDisjunction(self)
248	}
249
250	/// Displays this set as a conjunction.
251	///
252	/// # Example
253	///
254	/// ```
255	/// # use jstrict::{Kind, KindSet};
256	/// let set = Kind::Null | Kind::String | Kind::Object;
257	/// assert_eq!(set.as_conjunction().to_string(), "null, string and object");
258	/// assert_eq!(KindSet::ARRAY.as_conjunction().to_string(), "array");
259	/// assert_eq!(KindSet::all().as_conjunction().to_string(), "anything");
260	/// assert_eq!(KindSet::none().as_conjunction().to_string(), "nothing");
261	/// ```
262	#[must_use]
263	pub const fn as_conjunction(self) -> KindSetConjunction {
264		KindSetConjunction(self)
265	}
266}
267
268impl BitOr for KindSet {
269	type Output = Self;
270
271	fn bitor(self, other: Self) -> Self {
272		Self(self.0 | other.0)
273	}
274}
275
276impl BitOrAssign for KindSet {
277	fn bitor_assign(&mut self, other: Self) {
278		self.0 |= other.0;
279	}
280}
281
282impl BitAnd for KindSet {
283	type Output = Self;
284
285	fn bitand(self, other: Self) -> Self {
286		Self(self.0 & other.0)
287	}
288}
289
290impl BitAndAssign for KindSet {
291	fn bitand_assign(&mut self, other: Self) {
292		self.0 &= other.0;
293	}
294}
295
296impl IntoIterator for &KindSet {
297	type IntoIter = KindSetIter;
298	type Item = Kind;
299
300	fn into_iter(self) -> KindSetIter {
301		self.iter()
302	}
303}
304
305impl IntoIterator for KindSet {
306	type IntoIter = KindSetIter;
307	type Item = Kind;
308
309	fn into_iter(self) -> KindSetIter {
310		self.iter()
311	}
312}
313
314impl fmt::Display for KindSet {
315	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
316		for (i, kind) in self.into_iter().enumerate() {
317			if i > 0 {
318				f.write_str(", ")?;
319			}
320
321			kind.fmt(f)?;
322		}
323
324		Ok(())
325	}
326}
327
328/// Displays a `KindSet` as a disjunction.
329#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
330pub struct KindSetDisjunction(pub KindSet);
331
332impl fmt::Display for KindSetDisjunction {
333	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
334		if self.0 == KindSet::all() {
335			f.write_str("anything")
336		} else {
337			let mut iter = self.0.into_iter();
338			match iter.next_back() {
339				Some(last) => {
340					if let Some(first) = iter.next() {
341						first.fmt(f)?;
342						for k in iter {
343							f.write_str(", ")?;
344							k.fmt(f)?;
345						}
346						f.write_str(" or ")?;
347					}
348
349					last.fmt(f)
350				}
351				None => f.write_str("nothing"),
352			}
353		}
354	}
355}
356
357/// Displays a `KindSet` as a conjunction.
358#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
359pub struct KindSetConjunction(pub KindSet);
360
361impl fmt::Display for KindSetConjunction {
362	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
363		if self.0 == KindSet::all() {
364			f.write_str("anything")
365		} else {
366			let mut iter = self.0.into_iter();
367			match iter.next_back() {
368				Some(last) => {
369					if let Some(first) = iter.next() {
370						first.fmt(f)?;
371						for k in iter {
372							f.write_str(", ")?;
373							k.fmt(f)?;
374						}
375						f.write_str(" and ")?;
376					}
377
378					last.fmt(f)
379				}
380				None => f.write_str("nothing"),
381			}
382		}
383	}
384}