Improve error reporting

This commit is contained in:
Dirkjan Ochtman 2022-11-23 18:53:40 -08:00
parent f6e22b3e31
commit eb2cfd59f9
5 changed files with 54 additions and 27 deletions

View File

@ -132,7 +132,7 @@ fn deserialize_wrapped_enum(
let data = match node { let data = match node {
Node::Open(data) => data, Node::Open(data) => data,
_ => return Err(Error::UnexpectedState), _ => return Err(Error::UnexpectedState("unexpected node type for wrapped enum variant")),
}; };
let id = deserializer.element_id(&data)?; let id = deserializer.element_id(&data)?;
@ -141,7 +141,7 @@ fn deserialize_wrapped_enum(
}; };
if let Some(_) = deserializer.next() { if let Some(_) = deserializer.next() {
return Err(Error::UnexpectedState); return Err(Error::UnexpectedState("unexpected node after wrapped enum variant"));
} }
Ok(value) Ok(value)
@ -278,7 +278,7 @@ fn deserialize_struct(
} }
} }
} }
_ => return Err(Error::UnexpectedState), node => return Err(Error::UnexpectedNode(format!("{:?}", node))),
} }
} }

View File

@ -36,7 +36,11 @@ impl<'cx, 'xml> Deserializer<'cx, 'xml> {
if element { if element {
match self.next() { match self.next() {
Some(Ok(_)) => return Err(Error::UnexpectedState), Some(Ok(_)) => {
return Err(Error::UnexpectedState(
"found element while expecting scalar",
))
}
Some(Err(e)) => return Err(e), Some(Err(e)) => return Err(e),
_ => {} _ => {}
} }
@ -112,7 +116,7 @@ impl<'xml> Iterator for Deserializer<'_, 'xml> {
return None; return None;
} }
Some(Err(Error::UnexpectedState)) Some(Err(Error::UnexpectedState("close element mismatch")))
} }
} }
@ -133,7 +137,7 @@ impl<'xml> Context<'xml> {
let root = match new.next() { let root = match new.next() {
Some(result) => match result? { Some(result) => match result? {
Node::Open(element) => element, Node::Open(element) => element,
_ => return Err(Error::UnexpectedState), _ => return Err(Error::UnexpectedState("first node does not open element")),
}, },
None => return Err(Error::UnexpectedEndOfStream), None => return Err(Error::UnexpectedEndOfStream),
}; };
@ -217,7 +221,11 @@ impl<'xml> Iterator for Context<'xml> {
ElementEnd::Open => { ElementEnd::Open => {
let level = match current { let level = match current {
Some(level) => level, Some(level) => level,
None => return Some(Err(Error::UnexpectedState)), None => {
return Some(Err(Error::UnexpectedState(
"opening element with no parent",
)))
}
}; };
let element = Element { let element = Element {
@ -232,7 +240,11 @@ impl<'xml> Iterator for Context<'xml> {
ElementEnd::Close(prefix, v) => { ElementEnd::Close(prefix, v) => {
let level = match self.stack.pop() { let level = match self.stack.pop() {
Some(level) => level, Some(level) => level,
None => return Some(Err(Error::UnexpectedState)), None => {
return Some(Err(Error::UnexpectedState(
"closing element without parent",
)))
}
}; };
let prefix = (!prefix.is_empty()).then_some(prefix.as_str()); let prefix = (!prefix.is_empty()).then_some(prefix.as_str());
@ -243,7 +255,9 @@ impl<'xml> Iterator for Context<'xml> {
local: level.local, local: level.local,
})) }))
} }
false => return Some(Err(Error::UnexpectedState)), false => {
return Some(Err(Error::UnexpectedState("close element mismatch")))
}
} }
} }
ElementEnd::Empty => { ElementEnd::Empty => {
@ -259,14 +273,22 @@ impl<'xml> Iterator for Context<'xml> {
if prefix.is_empty() && local.as_str() == "xmlns" { if prefix.is_empty() && local.as_str() == "xmlns" {
match &mut current { match &mut current {
Some(level) => level.default_ns = Some(value.as_str()), Some(level) => level.default_ns = Some(value.as_str()),
None => return Some(Err(Error::UnexpectedState)), None => {
return Some(Err(Error::UnexpectedState(
"attribute without element context",
)))
}
} }
} else if prefix.as_str() == "xmlns" { } else if prefix.as_str() == "xmlns" {
match &mut current { match &mut current {
Some(level) => { Some(level) => {
level.prefixes.insert(local.as_str(), value.as_str()); level.prefixes.insert(local.as_str(), value.as_str());
} }
None => return Some(Err(Error::UnexpectedState)), None => {
return Some(Err(Error::UnexpectedState(
"attribute without element context",
)))
}
} }
} else { } else {
let prefix = (!prefix.is_empty()).then_some(prefix.as_str()); let prefix = (!prefix.is_empty()).then_some(prefix.as_str());
@ -280,7 +302,7 @@ impl<'xml> Iterator for Context<'xml> {
Ok(Token::Text { text }) => { Ok(Token::Text { text }) => {
return Some(Ok(Node::Text(text.as_str()))); return Some(Ok(Node::Text(text.as_str())));
} }
Ok(_) => return Some(Err(Error::UnexpectedToken)), Ok(token) => return Some(Err(Error::UnexpectedToken(format!("{:?}", token)))),
Err(e) => return Some(Err(Error::Parse(e))), Err(e) => return Some(Err(Error::Parse(e))),
} }
} }

View File

@ -341,14 +341,14 @@ where
let mut nested = deserializer.nested(data); let mut nested = deserializer.nested(data);
result.push(<T as FromXml<'xml>>::deserialize(&mut nested)?) result.push(<T as FromXml<'xml>>::deserialize(&mut nested)?)
} }
_ => return Err(Error::UnexpectedState), _ => return Err(Error::UnexpectedState("unexpected list element name")),
} }
} }
(Kind::Vec | Kind::Element(_), Node::Open(data)) => { (Kind::Vec | Kind::Element(_), Node::Open(data)) => {
let mut nested = deserializer.nested(data); let mut nested = deserializer.nested(data);
result.push(<T as FromXml<'xml>>::deserialize(&mut nested)?) result.push(<T as FromXml<'xml>>::deserialize(&mut nested)?)
} }
_ => return Err(Error::UnexpectedState), _ => return Err(Error::UnexpectedState("unexpected node for list")),
} }
} }

View File

@ -49,8 +49,8 @@ pub fn from_str<'xml, T: FromXml<'xml>>(input: &'xml str) -> Result<T, Error> {
let (mut context, root) = Context::new(input)?; let (mut context, root) = Context::new(input)?;
let id = context.element_id(&root)?; let id = context.element_id(&root)?;
let expected = match T::KIND { let expected = match T::KIND {
Kind::Scalar => return Err(Error::UnexpectedState), Kind::Scalar => return Err(Error::UnexpectedState("found scalar as root")),
Kind::Vec => return Err(Error::UnexpectedState), Kind::Vec => return Err(Error::UnexpectedState("found list as root")),
Kind::Element(expected) => expected, Kind::Element(expected) => expected,
}; };
@ -96,12 +96,14 @@ pub enum Error {
MissingTag, MissingTag,
#[error("missing value")] #[error("missing value")]
MissingValue, MissingValue,
#[error("unexpected token")] #[error("unexpected token: {0}")]
UnexpectedToken, UnexpectedToken(String),
#[error("missing prefix")] #[error("missing prefix")]
MissingdPrefix, MissingdPrefix,
#[error("unexpected state")] #[error("unexpected node: {0}")]
UnexpectedState, UnexpectedNode(String),
#[error("unexpected state: {0}")]
UnexpectedState(&'static str),
#[error("expected scalar")] #[error("expected scalar")]
ExpectedScalar, ExpectedScalar,
#[error("wrong namespace")] #[error("wrong namespace")]

View File

@ -35,7 +35,7 @@ impl<'xml, W: fmt::Write + ?Sized> Serializer<'xml, W> {
scalar: bool, scalar: bool,
) -> Result<Option<&'static str>, Error> { ) -> Result<Option<&'static str>, Error> {
if self.state != State::Element { if self.state != State::Element {
return Err(Error::UnexpectedState); return Err(Error::UnexpectedState("invalid state for element start"));
} }
let prefix = match ns == self.default_ns { let prefix = match ns == self.default_ns {
@ -70,13 +70,16 @@ impl<'xml, W: fmt::Write + ?Sized> Serializer<'xml, W> {
value: &V, value: &V,
) -> Result<(), Error> { ) -> Result<(), Error> {
if self.state != State::Attribute { if self.state != State::Attribute {
return Err(Error::UnexpectedState); return Err(Error::UnexpectedState("invalid state for attribute"));
} }
match ns == self.default_ns { match ns == self.default_ns {
true => self.output.write_fmt(format_args!(" {name}=\""))?, true => self.output.write_fmt(format_args!(" {name}=\""))?,
false => { false => {
let prefix = self.prefixes.get(ns).ok_or(dbg!(Error::UnexpectedState))?; let prefix = self
.prefixes
.get(ns)
.ok_or(Error::UnexpectedState("unknown prefix"))?;
self.output.write_fmt(format_args!(" {prefix}:{name}=\""))?; self.output.write_fmt(format_args!(" {prefix}:{name}=\""))?;
} }
} }
@ -90,7 +93,7 @@ impl<'xml, W: fmt::Write + ?Sized> Serializer<'xml, W> {
pub fn write_str<V: fmt::Display + ?Sized>(&mut self, value: &V) -> Result<(), Error> { pub fn write_str<V: fmt::Display + ?Sized>(&mut self, value: &V) -> Result<(), Error> {
if !matches!(self.state, State::Element | State::Scalar) { if !matches!(self.state, State::Element | State::Scalar) {
return Err(Error::UnexpectedState); return Err(Error::UnexpectedState("invalid state for scalar"));
} }
self.output.write_fmt(format_args!("{}", value))?; self.output.write_fmt(format_args!("{}", value))?;
@ -100,7 +103,7 @@ impl<'xml, W: fmt::Write + ?Sized> Serializer<'xml, W> {
pub fn end_start(&mut self) -> Result<(), Error> { pub fn end_start(&mut self) -> Result<(), Error> {
if self.state != State::Attribute { if self.state != State::Attribute {
return Err(Error::UnexpectedState); return Err(Error::UnexpectedState("invalid state for element end"));
} }
self.output.write_char('>')?; self.output.write_char('>')?;
@ -110,7 +113,7 @@ impl<'xml, W: fmt::Write + ?Sized> Serializer<'xml, W> {
pub fn write_close(&mut self, prefix: Option<&str>, name: &str) -> Result<(), Error> { pub fn write_close(&mut self, prefix: Option<&str>, name: &str) -> Result<(), Error> {
if self.state != State::Element { if self.state != State::Element {
return Err(Error::UnexpectedState); return Err(Error::UnexpectedState("invalid state for close element"));
} }
match prefix { match prefix {
@ -123,7 +126,7 @@ impl<'xml, W: fmt::Write + ?Sized> Serializer<'xml, W> {
pub fn push<const N: usize>(&mut self, new: Context<N>) -> Result<Context<N>, Error> { pub fn push<const N: usize>(&mut self, new: Context<N>) -> Result<Context<N>, Error> {
if self.state != State::Attribute { if self.state != State::Attribute {
return Err(Error::UnexpectedState); return Err(Error::UnexpectedState("invalid state for attribute"));
} }
let mut old = Context::default(); let mut old = Context::default();