cfg_symbol/
symbol.rs

1//! Definitions for our grammar symbol type.
2//!
3//! A symbol can be thought of as simply an integer,
4//! which only works for the `SymbolSource` where it
5//! was grabbed from, or a `SymbolSource` with a similar
6//! symbol at that integer value, such as one in a cloned grammar.
7//! In short, best to be careful not to mix symbols between different
8//! grammars.
9//!
10//! # TODO
11//!
12//! Allow choice between u8, u16 and u32 for symbols.
13
14use std::num::{NonZeroU8, NonZeroU16, NonZeroU32};
15
16///
17pub trait SymbolPrimitive: TryFrom<NonZeroU32> + Into<NonZeroU32> + Copy {
18    /// Unsigned integer type that covers all possible values of `Self`.
19    type BasePrimitive: From<Self> + TryInto<Self> + From<u8>;
20
21    /// Highest available numeric value for `Self`.
22    ///
23    /// For example, for `NonZeroU16`, this will be `u16::MAX`.
24    const MAX: u32;
25}
26
27impl SymbolPrimitive for NonZeroU8 {
28    type BasePrimitive = u8;
29    const MAX: u32 = u8::MAX as u32;
30}
31
32impl SymbolPrimitive for NonZeroU16 {
33    type BasePrimitive = u16;
34    const MAX: u32 = u16::MAX as u32;
35}
36
37impl SymbolPrimitive for NonZeroU32 {
38    type BasePrimitive = u32;
39    const MAX: u32 = u32::MAX;
40}
41
42/// Our common grammar symbol type.
43#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
44// miniserde impls are further below
45#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
46pub struct Symbol<T: SymbolPrimitive = NonZeroU32> {
47    pub(crate) n: T,
48}
49
50impl<T: SymbolPrimitive> Default for Symbol<T> {
51    fn default() -> Self {
52        Self::first()
53    }
54}
55
56impl<T: SymbolPrimitive> Symbol<T> {
57    /// Returns the symbol with the lowest numeric value.
58    pub fn first() -> Self {
59        let one: T::BasePrimitive = 1u8.into();
60        Symbol {
61            n: one
62                .try_into()
63                .ok()
64                .expect("unreachable: could not convert 1u8"),
65        }
66    }
67
68    /// Returns the symbol's numeric value.
69    ///
70    /// # Panics
71    ///
72    /// May fail on 16-bit platforms in case of overflow for `usize`.
73    pub fn usize(&self) -> usize {
74        let val = self.n.into().get();
75        #[cfg(target_pointer_width = "16")]
76        assert!(val <= 0xFFFF);
77        val as usize - 1
78    }
79}
80
81impl<T: SymbolPrimitive> Into<u32> for Symbol<T> {
82    fn into(self) -> u32 {
83        let nzu32: NonZeroU32 = self.n.into();
84        nzu32.get() - 1
85    }
86}
87
88mod miniserde_impls {
89    use super::{Symbol, SymbolPrimitive};
90    use miniserde::de::{Deserialize, Visitor};
91    use miniserde::{Error, Result, make_place};
92    use miniserde::{Serialize, de, ser};
93    use std::num::NonZeroU32;
94
95    make_place!(Place);
96
97    impl<T: SymbolPrimitive> Visitor for Place<Symbol<T>> {
98        fn nonnegative(&mut self, n: u64) -> Result<()> {
99            if n < T::MAX as u64 {
100                if let Some(Ok(nonzero_num)) =
101                    NonZeroU32::new((n + 1) as u32).map(|n| TryInto::<T>::try_into(n))
102                {
103                    self.out = Some(Symbol { n: nonzero_num });
104                    Ok(())
105                } else {
106                    Err(Error)
107                }
108            } else {
109                Err(Error)
110            }
111        }
112    }
113
114    impl<T: SymbolPrimitive> Deserialize for Symbol<T> {
115        fn begin(out: &mut Option<Self>) -> &mut dyn de::Visitor {
116            Place::new(out)
117        }
118    }
119
120    impl<T: SymbolPrimitive> Serialize for Symbol<T> {
121        fn begin(&self) -> ser::Fragment<'_> {
122            // Q: Why cast u32 to u64?
123            // A: Miniserde only accepts wide integers.
124            //    It does not matter what's the width in case of
125            //    JSON, and this is the only format miniserde accepts.
126            let n: u32 = (*self).into();
127            ser::Fragment::U64(n as u64)
128        }
129    }
130}
131
132#[cfg(feature = "nanoserde")]
133impl nanoserde::DeBin for Symbol<NonZeroU32> {
134    fn de_bin(offset: &mut usize, bytes: &[u8]) -> Result<Self, nanoserde::DeBinErr> {
135        Ok(Symbol {
136            n: u32::de_bin(offset, bytes)?.try_into().unwrap(),
137        })
138    }
139}
140
141#[cfg(feature = "nanoserde")]
142impl nanoserde::SerBin for Symbol<NonZeroU32> {
143    fn ser_bin(&self, output: &mut Vec<u8>) {
144        u32::ser_bin(&self.n.get(), output);
145    }
146}