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}