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