chumsky/
util.rs

1//! Utility items used throughout the crate.
2
3use super::*;
4
5use core::hash::Hasher;
6
7/// A value that may be a `T` or a mutable reference to a `T`.
8pub type MaybeMut<'a, T> = Maybe<T, &'a mut T>;
9
10/// A value that may be a `T` or a shared reference to a `T`.
11pub type MaybeRef<'a, T> = Maybe<T, &'a T>;
12
13/// A type that can represent a borrowed reference to a `T` or a value of `T`.
14///
15/// Used internally to facilitate zero-copy manipulation of tokens during error generation (see [`Error`]).
16#[derive(Copy, Clone)]
17pub enum Maybe<T, R: Deref<Target = T>> {
18    /// We have a reference to `T`.
19    Ref(R),
20    /// We have a value of `T`.
21    Val(T),
22}
23
24impl<T: PartialEq, R: Deref<Target = T>> PartialEq for Maybe<T, R> {
25    #[inline]
26    fn eq(&self, other: &Self) -> bool {
27        **self == **other
28    }
29}
30
31impl<T: Eq, R: Deref<Target = T>> Eq for Maybe<T, R> {}
32
33impl<T: PartialOrd, R: Deref<Target = T>> PartialOrd for Maybe<T, R> {
34    #[inline]
35    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
36        (**self).partial_cmp(&**other)
37    }
38}
39
40impl<T: Ord, R: Deref<Target = T>> Ord for Maybe<T, R> {
41    #[inline]
42    fn cmp(&self, other: &Self) -> Ordering {
43        (**self).cmp(&**other)
44    }
45}
46
47impl<T: Hash, R: Deref<Target = T>> Hash for Maybe<T, R> {
48    #[inline]
49    fn hash<H: Hasher>(&self, state: &mut H) {
50        T::hash(&**self, state)
51    }
52}
53
54impl<T: fmt::Debug, R: Deref<Target = T>> fmt::Debug for Maybe<T, R> {
55    #[inline]
56    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
57        T::fmt(&**self, f)
58    }
59}
60
61impl<T, R: Deref<Target = T>> Maybe<T, R> {
62    /// Convert this [`Maybe<T, _>`] into a `T`, cloning the inner value if necessary.
63    #[inline]
64    pub fn into_inner(self) -> T
65    where
66        T: Clone,
67    {
68        match self {
69            Self::Ref(x) => x.clone(),
70            Self::Val(x) => x,
71        }
72    }
73
74    /// Convert this [`Maybe<T, _>`] into an owned version of itself, cloning the inner reference if required.
75    #[inline]
76    pub fn into_owned<U>(self) -> Maybe<T, U>
77    where
78        T: Clone,
79        U: Deref<Target = T>,
80    {
81        Maybe::Val(self.into_inner())
82    }
83}
84
85impl<T, R: Deref<Target = T>> Deref for Maybe<T, R> {
86    type Target = T;
87
88    #[inline]
89    fn deref(&self) -> &Self::Target {
90        match self {
91            Self::Ref(x) => x,
92            Self::Val(x) => x,
93        }
94    }
95}
96
97impl<T, R: DerefMut<Target = T>> DerefMut for Maybe<T, R> {
98    #[inline]
99    fn deref_mut(&mut self) -> &mut Self::Target {
100        match self {
101            Self::Ref(x) => &mut *x,
102            Self::Val(x) => x,
103        }
104    }
105}
106
107impl<T> From<T> for Maybe<T, &T> {
108    #[inline]
109    fn from(x: T) -> Self {
110        Self::Val(x)
111    }
112}
113
114impl<T> From<T> for Maybe<T, &mut T> {
115    #[inline]
116    fn from(x: T) -> Self {
117        Self::Val(x)
118    }
119}
120
121impl<'a, T> From<&'a T> for Maybe<T, &'a T> {
122    #[inline]
123    fn from(x: &'a T) -> Self {
124        Self::Ref(x)
125    }
126}
127
128impl<'a, T> From<&'a mut T> for Maybe<T, &'a mut T> {
129    #[inline]
130    fn from(x: &'a mut T) -> Self {
131        Self::Ref(x)
132    }
133}
134
135#[cfg(feature = "serde")]
136impl<T: Serialize, R: Deref<Target = T>> Serialize for Maybe<T, R> {
137    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
138    where
139        S: Serializer,
140    {
141        serializer.serialize_newtype_struct("Maybe", &**self)
142    }
143}
144
145#[cfg(feature = "serde")]
146impl<'de, T: Deserialize<'de>, R: Deref<Target = T>> Deserialize<'de> for Maybe<T, R> {
147    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
148    where
149        D: Deserializer<'de>,
150    {
151        struct MaybeVisitor<T, R>(PhantomData<(T, R)>);
152
153        impl<'de2, T: Deserialize<'de2>, R: Deref<Target = T>> Visitor<'de2> for MaybeVisitor<T, R> {
154            type Value = Maybe<T, R>;
155
156            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
157                write!(formatter, "a Maybe")
158            }
159
160            fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
161            where
162                D: Deserializer<'de2>,
163            {
164                T::deserialize(deserializer).map(Maybe::Val)
165            }
166        }
167
168        deserializer.deserialize_newtype_struct("Maybe", MaybeVisitor(PhantomData))
169    }
170}
171
172mod ref_or_val_sealed {
173    pub trait Sealed<T> {}
174}
175
176/// An trait that allows abstracting over values of or references to a `T`.
177///
178/// Some [`Input`]s can only generate tokens by-reference (like `&[T]` -> `&T`), and some can only generate tokens
179/// by-value (like `&str` -> `char`). This trait allows chumsky to handle both kinds of input.
180///
181/// The trait is sealed: you cannot implement it yourself.
182pub trait IntoMaybe<'src, T: 'src>:
183    ref_or_val_sealed::Sealed<T> + Borrow<T> + Into<MaybeRef<'src, T>>
184{
185    /// Project the referential properties of this type on to another type.
186    ///
187    /// For example, `<&Foo>::Proj<Bar> = &Bar` but `<Foo>::Proj<Bar> = Bar`.
188    #[doc(hidden)]
189    type Proj<U: 'src>: IntoMaybe<'src, U>;
190
191    #[doc(hidden)]
192    fn map_maybe<R: 'src>(
193        self,
194        f: impl FnOnce(&'src T) -> &'src R,
195        g: impl FnOnce(T) -> R,
196    ) -> Self::Proj<R>;
197}
198
199impl<T> ref_or_val_sealed::Sealed<T> for &T {}
200impl<'src, T> IntoMaybe<'src, T> for &'src T {
201    type Proj<U: 'src> = &'src U;
202    fn map_maybe<R: 'src>(
203        self,
204        f: impl FnOnce(&'src T) -> &'src R,
205        _g: impl FnOnce(T) -> R,
206    ) -> Self::Proj<R> {
207        f(self)
208    }
209}
210
211impl<T> ref_or_val_sealed::Sealed<T> for T {}
212impl<'src, T: 'src> IntoMaybe<'src, T> for T {
213    type Proj<U: 'src> = U;
214    fn map_maybe<R: 'src>(
215        self,
216        _f: impl FnOnce(&'src T) -> &'src R,
217        g: impl FnOnce(T) -> R,
218    ) -> Self::Proj<R> {
219        g(self)
220    }
221}