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 happens when the tree has more nodes than the flavor's
69 /// [`Width`][crate::Flavor::Width] can address, or when a span would exceed
70 /// its [`Index`][crate::Flavor::Index]. A narrow width such as `u8` makes
71 /// this easy to reach.
72 ///
73 /// # Examples
74 ///
75 /// This is an example where we're trying to build a really small tree using
76 /// u8 pointers:
77 ///
78 /// ```
79 /// use syntree::{Builder, Error};
80 ///
81 /// syntree::flavor! {
82 /// struct CustomFlavor {
83 /// type Index = u32;
84 /// type Width = u8;
85 /// }
86 /// }
87 ///
88 /// let mut tree: Builder<_, CustomFlavor> = Builder::new_with();
89 ///
90 /// for d in 0..u8::MAX {
91 /// tree.token(d, 1)?;
92 /// }
93 ///
94 /// assert_eq!(tree.token(255, 1), Err(Error::Overflow));
95 /// # Ok::<_, Box<dyn core::error::Error>>(())
96 /// ```
97 Overflow,
98 /// The node of the given id is missing.
99 ///
100 /// # Examples
101 ///
102 /// The following showcases what could happen if you mix checkpoints from
103 /// two compatible trees:
104 ///
105 /// ```
106 /// use syntree::{Builder, Error};
107 ///
108 /// let mut a = Builder::new();
109 /// let mut b = Builder::new();
110 ///
111 /// b.open("child")?;
112 /// b.close()?;
113 ///
114 /// let c = b.checkpoint()?;
115 ///
116 /// assert_eq!(a.close_at(&c, "operation"), Err(Error::MissingNode(1)));
117 /// # Ok::<_, Box<dyn core::error::Error>>(())
118 /// ```
119 MissingNode(usize),
120 /// An error raised by the particular [Flavor] in use.
121 ///
122 /// [Flavor]: crate::Flavor
123 Flavor(E),
124}
125
126impl<E> From<E> for Error<E> {
127 #[inline]
128 fn from(error: E) -> Self {
129 Error::Flavor(error)
130 }
131}
132
133impl<E> core::error::Error for Error<E>
134where
135 E: 'static + core::error::Error,
136{
137 #[inline]
138 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
139 match self {
140 Error::Flavor(error) => Some(error),
141 _ => None,
142 }
143 }
144}
145
146impl<E> fmt::Display for Error<E>
147where
148 E: fmt::Display,
149{
150 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
151 match self {
152 Error::CloseError => {
153 write!(f, "no node being built")
154 }
155 Error::BuildError => {
156 write!(f, "tree is currently being built")
157 }
158 Error::CloseAtError => {
159 write!(
160 f,
161 "trying to close a node which is not a sibling of the checkpoint being closed"
162 )
163 }
164 Error::Overflow => {
165 write!(f, "numerical overflow")
166 }
167 Error::MissingNode(p) => {
168 write!(f, "missing node with id `{p}`")
169 }
170 Error::Flavor(error) => error.fmt(f),
171 }
172 }
173}