syntree/
error.rs

1use core::convert::Infallible;
2use core::fmt;
3
4/// Errors raised while building a tree.
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6#[non_exhaustive]
7pub enum Error<E = Infallible> {
8    /// Error raised by [Builder::close][crate::Builder::close] if there
9    /// currently is no node being built.
10    ///
11    /// # Examples
12    ///
13    /// ```
14    /// use syntree::{Builder, Error};
15    ///
16    /// let mut tree = Builder::new();
17    ///
18    /// tree.open("root")?;
19    /// tree.close()?;
20    ///
21    /// // Syntax::Root and Syntax::Child is left open.
22    /// assert_eq!(tree.close(), Err(Error::CloseError));
23    /// # Ok::<_, Box<dyn core::error::Error>>(())
24    /// ```
25    CloseError,
26    /// Error raised by [Builder::build][crate::Builder::build] if the
27    /// tree isn't correctly balanced.
28    ///
29    /// # Examples
30    ///
31    /// ```
32    /// use syntree::{Builder, Error};
33    ///
34    /// let mut tree = Builder::new();
35    ///
36    /// tree.open("number")?;
37    /// tree.token("lit", 3)?;
38    /// tree.close()?;
39    ///
40    /// tree.open("number")?;
41    ///
42    /// // Syntax::Number is left open.
43    /// assert_eq!(tree.build(), Err(Error::BuildError));
44    /// # Ok::<_, Box<dyn core::error::Error>>(())
45    /// ```
46    BuildError,
47    /// Error raised by [Builder::close_at][crate::Builder::close_at] if
48    /// we're not trying to close at a sibling node.
49    ///
50    /// # Examples
51    ///
52    /// ```
53    /// use syntree::{Builder, Error};
54    ///
55    /// let mut tree = Builder::new();
56    ///
57    /// let c = tree.checkpoint()?;
58    ///
59    /// tree.open("child")?;
60    /// tree.token("token", 3)?;
61    ///
62    /// assert_eq!(tree.close_at(&c, "operation"), Err(Error::CloseAtError));
63    /// # Ok::<_, Box<dyn core::error::Error>>(())
64    /// ```
65    CloseAtError,
66    /// Numerical overflow.
67    ///
68    /// This only happens under extreme circumstances or if a feature is enabled
69    /// which narrows the width of an identifier to the degree that this error
70    /// is easier to accomplish.
71    ///
72    /// # Examples
73    ///
74    /// This is an example where we're trying to build a really small tree using
75    /// u8 pointers:
76    ///
77    /// ```
78    /// use syntree::{Builder, Error};
79    ///
80    /// syntree::flavor! {
81    ///     struct CustomFlavor {
82    ///         type Index = u32;
83    ///         type Width = u8;
84    ///     }
85    /// }
86    ///
87    /// let mut tree: Builder<_, CustomFlavor> = Builder::new_with();
88    ///
89    /// for d in 0..u8::MAX {
90    ///     tree.token(d, 1)?;
91    /// }
92    ///
93    /// assert_eq!(tree.token(255, 1), Err(Error::Overflow));
94    /// # Ok::<_, Box<dyn core::error::Error>>(())
95    /// ```
96    Overflow,
97    /// The node of the given id is missing.
98    ///
99    /// # Examples
100    ///
101    /// The following showcases what could happen if you mix checkpoints from
102    /// two compatible trees:
103    ///
104    /// ```
105    /// use syntree::{Builder, Error};
106    ///
107    /// let mut a = Builder::new();
108    /// let mut b = Builder::new();
109    ///
110    /// b.open("child")?;
111    /// b.close()?;
112    ///
113    /// let c = b.checkpoint()?;
114    ///
115    /// assert_eq!(a.close_at(&c, "operation"), Err(Error::MissingNode(0)));
116    /// # Ok::<_, Box<dyn core::error::Error>>(())
117    /// ```
118    MissingNode(usize),
119    /// An error raised by the particular [Flavor] in use.
120    ///
121    /// [Flavor]: crate::Flavor
122    Flavor(E),
123}
124
125impl<E> From<E> for Error<E> {
126    #[inline]
127    fn from(error: E) -> Self {
128        Error::Flavor(error)
129    }
130}
131
132impl<E> core::error::Error for Error<E>
133where
134    E: 'static + core::error::Error,
135{
136    #[inline]
137    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
138        match self {
139            Error::Flavor(error) => Some(error),
140            _ => None,
141        }
142    }
143}
144
145impl<E> fmt::Display for Error<E>
146where
147    E: fmt::Display,
148{
149    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150        match self {
151            Error::CloseError => {
152                write!(f, "no node being built")
153            }
154            Error::BuildError => {
155                write!(f, "tree is currently being built")
156            }
157            Error::CloseAtError => {
158                write!(
159                    f,
160                    "trying to close a node which is not a sibling of the checkpoint being closed"
161                )
162            }
163            Error::Overflow => {
164                write!(f, "numerical overflow")
165            }
166            Error::MissingNode(p) => {
167                write!(f, "missing node with id `{p}`")
168            }
169            Error::Flavor(error) => error.fmt(f),
170        }
171    }
172}