parsers: use Error type from xso
This is a large change and as such, it needs good motivation. Let me remind you of the ultimate goal: we want a derive macro which allows us to FromXml/IntoXml, and that derive macro should be usable from `xmpp_parsers` and other crates. For that, any code generated by the derive macro mustn't depend on any code in the `xmpp_parsers` crate, because you cannot name the crate you are in portably (`xmpp_parsers::..` wouldn't resolve within `xmpp_parsers`, and `crate::..` would point at other crates if the macro was used in other crates). We also want to interoperate with code already implementing `TryFrom<Element>` and `Into<Element>` on structs. This ultimately requires that we have an error type which is shared by the two implementations and that error type must be declared in the `xso` crate to be usable by the macros. Thus, we port the error type over to use the type declared in `xso`. This changes the structure of the error type greatly; I do not think that `xso` should have to know about all the different types we are parsing there and they don't deserve special treatment. Wrapping them in a `Box<dyn ..>` seems more appropriate.
This commit is contained in:
parent
b3e6e089da
commit
6ef8dbefa3
62 changed files with 916 additions and 892 deletions
|
|
@ -1,148 +0,0 @@
|
|||
// Copyright (c) 2017-2018 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
use std::error::Error as StdError;
|
||||
use std::fmt;
|
||||
|
||||
/// Contains one of the potential errors triggered while parsing an
|
||||
/// [Element](../struct.Element.html) into a specialised struct.
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// The usual error when parsing something.
|
||||
///
|
||||
/// TODO: use a structured error so the user can report it better, instead
|
||||
/// of a freeform string.
|
||||
ParseError(&'static str),
|
||||
|
||||
/// Element local-name/namespace mismatch
|
||||
///
|
||||
/// Returns the original element unaltered, as well as the expected ns and
|
||||
/// local-name.
|
||||
TypeMismatch(&'static str, &'static str, crate::Element),
|
||||
|
||||
/// Generated when some base64 content fails to decode, usually due to
|
||||
/// extra characters.
|
||||
Base64Error(base64::DecodeError),
|
||||
|
||||
/// Generated when text which should be an integer fails to parse.
|
||||
ParseIntError(std::num::ParseIntError),
|
||||
|
||||
/// Generated when text which should be a string fails to parse.
|
||||
ParseStringError(std::string::ParseError),
|
||||
|
||||
/// Generated when text which should be an IP address (IPv4 or IPv6) fails
|
||||
/// to parse.
|
||||
ParseAddrError(std::net::AddrParseError),
|
||||
|
||||
/// Generated when text which should be a [JID](../../jid/struct.Jid.html)
|
||||
/// fails to parse.
|
||||
JidParseError(jid::Error),
|
||||
|
||||
/// Generated when text which should be a
|
||||
/// [DateTime](../date/struct.DateTime.html) fails to parse.
|
||||
ChronoParseError(chrono::ParseError),
|
||||
}
|
||||
|
||||
impl Error {
|
||||
/// Converts the TypeMismatch error to a generic ParseError
|
||||
///
|
||||
/// This must be used when TryFrom is called on children to avoid confusing
|
||||
/// user code which assumes that TypeMismatch refers to the top level
|
||||
/// element only.
|
||||
pub(crate) fn hide_type_mismatch(self) -> Self {
|
||||
match self {
|
||||
Error::TypeMismatch(..) => Error::ParseError("Unexpected child element"),
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StdError for Error {
|
||||
fn cause(&self) -> Option<&dyn StdError> {
|
||||
match self {
|
||||
Error::ParseError(_) | Error::TypeMismatch(..) => None,
|
||||
Error::Base64Error(e) => Some(e),
|
||||
Error::ParseIntError(e) => Some(e),
|
||||
Error::ParseStringError(e) => Some(e),
|
||||
Error::ParseAddrError(e) => Some(e),
|
||||
Error::JidParseError(e) => Some(e),
|
||||
Error::ChronoParseError(e) => Some(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Error::ParseError(s) => write!(fmt, "parse error: {}", s),
|
||||
Error::TypeMismatch(ns, localname, element) => write!(
|
||||
fmt,
|
||||
"element type mismatch: expected {{{}}}{}, got {{{}}}{}",
|
||||
ns,
|
||||
localname,
|
||||
element.ns(),
|
||||
element.name()
|
||||
),
|
||||
Error::Base64Error(e) => write!(fmt, "base64 error: {}", e),
|
||||
Error::ParseIntError(e) => write!(fmt, "integer parsing error: {}", e),
|
||||
Error::ParseStringError(e) => write!(fmt, "string parsing error: {}", e),
|
||||
Error::ParseAddrError(e) => write!(fmt, "IP address parsing error: {}", e),
|
||||
Error::JidParseError(e) => write!(fmt, "JID parsing error: {}", e),
|
||||
Error::ChronoParseError(e) => write!(fmt, "time parsing error: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<base64::DecodeError> for Error {
|
||||
fn from(err: base64::DecodeError) -> Error {
|
||||
Error::Base64Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::num::ParseIntError> for Error {
|
||||
fn from(err: std::num::ParseIntError) -> Error {
|
||||
Error::ParseIntError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::string::ParseError> for Error {
|
||||
fn from(err: std::string::ParseError) -> Error {
|
||||
Error::ParseStringError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::net::AddrParseError> for Error {
|
||||
fn from(err: std::net::AddrParseError) -> Error {
|
||||
Error::ParseAddrError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<jid::Error> for Error {
|
||||
fn from(err: jid::Error) -> Error {
|
||||
Error::JidParseError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<chrono::ParseError> for Error {
|
||||
fn from(err: chrono::ParseError) -> Error {
|
||||
Error::ChronoParseError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Error> for xso::error::Error {
|
||||
fn from(other: Error) -> Self {
|
||||
match other {
|
||||
Error::ParseError(e) => Self::Other(e.to_string().into()),
|
||||
Error::TypeMismatch { .. } => Self::TypeMismatch,
|
||||
Error::Base64Error(e) => Self::TextParseError(Box::new(e)),
|
||||
Error::ParseIntError(e) => Self::TextParseError(Box::new(e)),
|
||||
Error::ParseStringError(e) => Self::TextParseError(Box::new(e)),
|
||||
Error::ParseAddrError(e) => Self::TextParseError(Box::new(e)),
|
||||
Error::JidParseError(e) => Self::TextParseError(Box::new(e)),
|
||||
Error::ChronoParseError(e) => Self::TextParseError(Box::new(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,13 @@
|
|||
|
||||
macro_rules! get_attr {
|
||||
($elem:ident, $attr:tt, $type:tt) => {
|
||||
get_attr!($elem, $attr, $type, value, value.parse()?)
|
||||
get_attr!(
|
||||
$elem,
|
||||
$attr,
|
||||
$type,
|
||||
value,
|
||||
value.parse().map_err(xso::error::Error::text_parse_error)?
|
||||
)
|
||||
};
|
||||
($elem:ident, $attr:tt, OptionEmpty, $value:ident, $func:expr) => {
|
||||
match $elem.attr($attr) {
|
||||
|
|
@ -25,30 +31,27 @@ macro_rules! get_attr {
|
|||
match $elem.attr($attr) {
|
||||
Some($value) => $func,
|
||||
None => {
|
||||
return Err(crate::util::error::Error::ParseError(concat!(
|
||||
"Required attribute '",
|
||||
$attr,
|
||||
"' missing."
|
||||
)));
|
||||
return Err(xso::error::Error::Other(
|
||||
concat!("Required attribute '", $attr, "' missing.").into(),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
}
|
||||
};
|
||||
($elem:ident, $attr:tt, RequiredNonEmpty, $value:ident, $func:expr) => {
|
||||
match $elem.attr($attr) {
|
||||
Some("") => {
|
||||
return Err(crate::util::error::Error::ParseError(concat!(
|
||||
"Required attribute '",
|
||||
$attr,
|
||||
"' must not be empty."
|
||||
)));
|
||||
return Err(xso::error::Error::Other(
|
||||
concat!("Required attribute '", $attr, "' must not be empty.").into(),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
Some($value) => $func,
|
||||
None => {
|
||||
return Err(crate::util::error::Error::ParseError(concat!(
|
||||
"Required attribute '",
|
||||
$attr,
|
||||
"' missing."
|
||||
)));
|
||||
return Err(xso::error::Error::Other(
|
||||
concat!("Required attribute '", $attr, "' missing.").into(),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -71,11 +74,11 @@ macro_rules! generate_attribute {
|
|||
),+
|
||||
}
|
||||
impl ::std::str::FromStr for $elem {
|
||||
type Err = crate::util::error::Error;
|
||||
fn from_str(s: &str) -> Result<$elem, crate::util::error::Error> {
|
||||
type Err = xso::error::Error;
|
||||
fn from_str(s: &str) -> Result<$elem, xso::error::Error> {
|
||||
Ok(match s {
|
||||
$($b => $elem::$a),+,
|
||||
_ => return Err(crate::util::error::Error::ParseError(concat!("Unknown value for '", $name, "' attribute."))),
|
||||
_ => return Err(xso::error::Error::Other(concat!("Unknown value for '", $name, "' attribute.")).into()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -104,11 +107,11 @@ macro_rules! generate_attribute {
|
|||
),+
|
||||
}
|
||||
impl ::std::str::FromStr for $elem {
|
||||
type Err = crate::util::error::Error;
|
||||
fn from_str(s: &str) -> Result<$elem, crate::util::error::Error> {
|
||||
type Err = xso::error::Error;
|
||||
fn from_str(s: &str) -> Result<$elem, xso::error::Error> {
|
||||
Ok(match s {
|
||||
$($b => $elem::$a),+,
|
||||
_ => return Err(crate::util::error::Error::ParseError(concat!("Unknown value for '", $name, "' attribute."))),
|
||||
_ => return Err(xso::error::Error::Other(concat!("Unknown value for '", $name, "' attribute.")).into()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -137,11 +140,11 @@ macro_rules! generate_attribute {
|
|||
None,
|
||||
}
|
||||
impl ::std::str::FromStr for $elem {
|
||||
type Err = crate::util::error::Error;
|
||||
fn from_str(s: &str) -> Result<Self, crate::util::error::Error> {
|
||||
type Err = xso::error::Error;
|
||||
fn from_str(s: &str) -> Result<Self, xso::error::Error> {
|
||||
Ok(match s {
|
||||
$value => $elem::$symbol,
|
||||
_ => return Err(crate::util::error::Error::ParseError(concat!("Unknown value for '", $name, "' attribute."))),
|
||||
_ => return Err(xso::error::Error::Other(concat!("Unknown value for '", $name, "' attribute."))),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -169,12 +172,12 @@ macro_rules! generate_attribute {
|
|||
False,
|
||||
}
|
||||
impl ::std::str::FromStr for $elem {
|
||||
type Err = crate::util::error::Error;
|
||||
fn from_str(s: &str) -> Result<Self, crate::util::error::Error> {
|
||||
type Err = xso::error::Error;
|
||||
fn from_str(s: &str) -> Result<Self, xso::error::Error> {
|
||||
Ok(match s {
|
||||
"true" | "1" => $elem::True,
|
||||
"false" | "0" => $elem::False,
|
||||
_ => return Err(crate::util::error::Error::ParseError(concat!("Unknown value for '", $name, "' attribute."))),
|
||||
_ => return Err(xso::error::Error::Other(concat!("Unknown value for '", $name, "' attribute."))),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -197,9 +200,9 @@ macro_rules! generate_attribute {
|
|||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct $elem(pub $type);
|
||||
impl ::std::str::FromStr for $elem {
|
||||
type Err = crate::util::error::Error;
|
||||
fn from_str(s: &str) -> Result<Self, crate::util::error::Error> {
|
||||
Ok($elem($type::from_str(s)?))
|
||||
type Err = xso::error::Error;
|
||||
fn from_str(s: &str) -> Result<Self, xso::error::Error> {
|
||||
Ok($elem($type::from_str(s).map_err(xso::error::Error::text_parse_error)?))
|
||||
}
|
||||
}
|
||||
impl ::minidom::IntoAttributeValue for $elem {
|
||||
|
|
@ -229,14 +232,14 @@ macro_rules! generate_element_enum {
|
|||
),+
|
||||
}
|
||||
impl ::std::convert::TryFrom<crate::Element> for $elem {
|
||||
type Error = crate::util::error::Error;
|
||||
fn try_from(elem: crate::Element) -> Result<$elem, crate::util::error::Error> {
|
||||
type Error = xso::error::FromElementError;
|
||||
fn try_from(elem: crate::Element) -> Result<$elem, xso::error::FromElementError> {
|
||||
check_ns_only!(elem, $name, $ns);
|
||||
check_no_children!(elem, $name);
|
||||
check_no_attributes!(elem, $name);
|
||||
Ok(match elem.name() {
|
||||
$($enum_name => $elem::$enum,)+
|
||||
_ => return Err(crate::util::error::Error::ParseError(concat!("This is not a ", $name, " element."))),
|
||||
_ => return Err(xso::error::Error::Other(concat!("This is not a ", $name, " element.")).into()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -265,14 +268,14 @@ macro_rules! generate_attribute_enum {
|
|||
),+
|
||||
}
|
||||
impl ::std::convert::TryFrom<crate::Element> for $elem {
|
||||
type Error = crate::util::error::Error;
|
||||
fn try_from(elem: crate::Element) -> Result<$elem, crate::util::error::Error> {
|
||||
type Error = xso::error::FromElementError;
|
||||
fn try_from(elem: crate::Element) -> Result<$elem, xso::error::FromElementError> {
|
||||
check_ns_only!(elem, $name, $ns);
|
||||
check_no_children!(elem, $name);
|
||||
check_no_unknown_attributes!(elem, $name, [$attr]);
|
||||
Ok(match get_attr!(elem, $attr, Required) {
|
||||
$($enum_name => $elem::$enum,)+
|
||||
_ => return Err(crate::util::error::Error::ParseError(concat!("Invalid ", $name, " ", $attr, " value."))),
|
||||
_ => return Err(xso::error::Error::Other(concat!("Invalid ", $name, " ", $attr, " value.")).into()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -294,11 +297,7 @@ macro_rules! check_self {
|
|||
};
|
||||
($elem:ident, $name:tt, $ns:ident, $pretty_name:tt) => {
|
||||
if !$elem.is($name, crate::ns::$ns) {
|
||||
return Err(crate::util::error::Error::TypeMismatch(
|
||||
$name,
|
||||
crate::ns::$ns,
|
||||
$elem,
|
||||
));
|
||||
return Err(xso::error::FromElementError::Mismatch($elem));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -309,11 +308,10 @@ macro_rules! check_child {
|
|||
};
|
||||
($elem:ident, $name:tt, $ns:ident, $pretty_name:tt) => {
|
||||
if !$elem.is($name, crate::ns::$ns) {
|
||||
return Err(crate::util::error::Error::ParseError(concat!(
|
||||
"This is not a ",
|
||||
$pretty_name,
|
||||
" element."
|
||||
)));
|
||||
return Err(xso::error::Error::Other(
|
||||
concat!("This is not a ", $pretty_name, " element.").into(),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -321,11 +319,10 @@ macro_rules! check_child {
|
|||
macro_rules! check_ns_only {
|
||||
($elem:ident, $name:tt, $ns:ident) => {
|
||||
if !$elem.has_ns(crate::ns::$ns) {
|
||||
return Err(crate::util::error::Error::ParseError(concat!(
|
||||
"This is not a ",
|
||||
$name,
|
||||
" element."
|
||||
)));
|
||||
return Err(xso::error::Error::Other(
|
||||
concat!("This is not a ", $name, " element.").into(),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -334,11 +331,10 @@ macro_rules! check_no_children {
|
|||
($elem:ident, $name:tt) => {
|
||||
#[cfg(not(feature = "disable-validation"))]
|
||||
for _ in $elem.children() {
|
||||
return Err(crate::util::error::Error::ParseError(concat!(
|
||||
"Unknown child in ",
|
||||
$name,
|
||||
" element."
|
||||
)));
|
||||
return Err(xso::error::Error::Other(
|
||||
concat!("Unknown child in ", $name, " element.").into(),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -347,11 +343,10 @@ macro_rules! check_no_attributes {
|
|||
($elem:ident, $name:tt) => {
|
||||
#[cfg(not(feature = "disable-validation"))]
|
||||
for _ in $elem.attrs() {
|
||||
return Err(crate::util::error::Error::ParseError(concat!(
|
||||
"Unknown attribute in ",
|
||||
$name,
|
||||
" element."
|
||||
)));
|
||||
return Err(xso::error::Error::Other(
|
||||
concat!("Unknown attribute in ", $name, " element.").into(),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -365,7 +360,7 @@ macro_rules! check_no_unknown_attributes {
|
|||
continue;
|
||||
}
|
||||
)*
|
||||
return Err(crate::util::error::Error::ParseError(concat!("Unknown attribute in ", $name, " element.")));
|
||||
return Err(xso::error::Error::Other(concat!("Unknown attribute in ", $name, " element.")).into());
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -377,9 +372,9 @@ macro_rules! generate_empty_element {
|
|||
pub struct $elem;
|
||||
|
||||
impl ::std::convert::TryFrom<crate::Element> for $elem {
|
||||
type Error = crate::util::error::Error;
|
||||
type Error = xso::error::FromElementError;
|
||||
|
||||
fn try_from(elem: crate::Element) -> Result<$elem, crate::util::error::Error> {
|
||||
fn try_from(elem: crate::Element) -> Result<$elem, xso::error::FromElementError> {
|
||||
check_self!(elem, $name, $ns);
|
||||
check_no_children!(elem, $name);
|
||||
check_no_attributes!(elem, $name);
|
||||
|
|
@ -402,8 +397,8 @@ macro_rules! generate_id {
|
|||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct $elem(pub String);
|
||||
impl ::std::str::FromStr for $elem {
|
||||
type Err = crate::util::error::Error;
|
||||
fn from_str(s: &str) -> Result<$elem, crate::util::error::Error> {
|
||||
type Err = xso::error::Error;
|
||||
fn from_str(s: &str) -> Result<$elem, xso::error::Error> {
|
||||
// TODO: add a way to parse that differently when needed.
|
||||
Ok($elem(String::from(s)))
|
||||
}
|
||||
|
|
@ -420,8 +415,8 @@ macro_rules! generate_elem_id {
|
|||
($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident) => (
|
||||
generate_elem_id!($(#[$meta])* $elem, $name, $ns, String);
|
||||
impl ::std::str::FromStr for $elem {
|
||||
type Err = crate::util::error::Error;
|
||||
fn from_str(s: &str) -> Result<$elem, crate::util::error::Error> {
|
||||
type Err = xso::error::Error;
|
||||
fn from_str(s: &str) -> Result<$elem, xso::error::Error> {
|
||||
// TODO: add a way to parse that differently when needed.
|
||||
Ok($elem(String::from(s)))
|
||||
}
|
||||
|
|
@ -432,13 +427,13 @@ macro_rules! generate_elem_id {
|
|||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct $elem(pub $type);
|
||||
impl ::std::convert::TryFrom<crate::Element> for $elem {
|
||||
type Error = crate::util::error::Error;
|
||||
fn try_from(elem: crate::Element) -> Result<$elem, crate::util::error::Error> {
|
||||
type Error = xso::error::FromElementError;
|
||||
fn try_from(elem: crate::Element) -> Result<$elem, xso::error::FromElementError> {
|
||||
check_self!(elem, $name, $ns);
|
||||
check_no_children!(elem, $name);
|
||||
check_no_attributes!(elem, $name);
|
||||
// TODO: add a way to parse that differently when needed.
|
||||
Ok($elem(elem.text().parse()?))
|
||||
Ok($elem(elem.text().parse().map_err(xso::error::Error::text_parse_error)?))
|
||||
}
|
||||
}
|
||||
impl From<$elem> for crate::Element {
|
||||
|
|
@ -507,7 +502,7 @@ macro_rules! do_parse {
|
|||
Ok($elem.text())
|
||||
};
|
||||
($elem:ident, $constructor:ident) => {
|
||||
$constructor::try_from($elem)
|
||||
$constructor::try_from($elem).map_err(xso::error::Error::from)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -520,13 +515,16 @@ macro_rules! do_parse_elem {
|
|||
};
|
||||
($temp:ident: Option = $constructor:ident => $elem:ident, $name:tt, $parent_name:tt) => {
|
||||
if $temp.is_some() {
|
||||
Err(crate::util::error::Error::ParseError(concat!(
|
||||
"Element ",
|
||||
$parent_name,
|
||||
" must not have more than one ",
|
||||
$name,
|
||||
" child."
|
||||
)))
|
||||
Err(xso::error::Error::Other(
|
||||
concat!(
|
||||
"Element ",
|
||||
$parent_name,
|
||||
" must not have more than one ",
|
||||
$name,
|
||||
" child."
|
||||
)
|
||||
.into(),
|
||||
))
|
||||
} else {
|
||||
match do_parse!($elem, $constructor) {
|
||||
Ok(v) => {
|
||||
|
|
@ -539,13 +537,16 @@ macro_rules! do_parse_elem {
|
|||
};
|
||||
($temp:ident: Required = $constructor:ident => $elem:ident, $name:tt, $parent_name:tt) => {
|
||||
if $temp.is_some() {
|
||||
Err(crate::util::error::Error::ParseError(concat!(
|
||||
"Element ",
|
||||
$parent_name,
|
||||
" must not have more than one ",
|
||||
$name,
|
||||
" child."
|
||||
)))
|
||||
Err(xso::error::Error::Other(
|
||||
concat!(
|
||||
"Element ",
|
||||
$parent_name,
|
||||
" must not have more than one ",
|
||||
$name,
|
||||
" child."
|
||||
)
|
||||
.into(),
|
||||
))
|
||||
} else {
|
||||
match do_parse!($elem, $constructor) {
|
||||
Ok(v) => {
|
||||
|
|
@ -558,13 +559,16 @@ macro_rules! do_parse_elem {
|
|||
};
|
||||
($temp:ident: Present = $constructor:ident => $elem:ident, $name:tt, $parent_name:tt) => {
|
||||
if $temp {
|
||||
Err(crate::util::error::Error::ParseError(concat!(
|
||||
"Element ",
|
||||
$parent_name,
|
||||
" must not have more than one ",
|
||||
$name,
|
||||
" child."
|
||||
)))
|
||||
Err(xso::error::Error::Other(
|
||||
concat!(
|
||||
"Element ",
|
||||
$parent_name,
|
||||
" must not have more than one ",
|
||||
$name,
|
||||
" child."
|
||||
)
|
||||
.into(),
|
||||
))
|
||||
} else {
|
||||
$temp = true;
|
||||
Ok(())
|
||||
|
|
@ -580,13 +584,9 @@ macro_rules! finish_parse_elem {
|
|||
$temp
|
||||
};
|
||||
($temp:ident: Required = $name:tt, $parent_name:tt) => {
|
||||
$temp.ok_or(crate::util::error::Error::ParseError(concat!(
|
||||
"Missing child ",
|
||||
$name,
|
||||
" in ",
|
||||
$parent_name,
|
||||
" element."
|
||||
)))?
|
||||
$temp.ok_or(xso::error::Error::Other(
|
||||
concat!("Missing child ", $name, " in ", $parent_name, " element.").into(),
|
||||
))?
|
||||
};
|
||||
($temp:ident: Present = $name:tt, $parent_name:tt) => {
|
||||
$temp
|
||||
|
|
@ -694,9 +694,9 @@ macro_rules! generate_element {
|
|||
}
|
||||
|
||||
impl ::std::convert::TryFrom<crate::Element> for $elem {
|
||||
type Error = crate::util::error::Error;
|
||||
type Error = xso::error::FromElementError;
|
||||
|
||||
fn try_from(mut elem: crate::Element) -> Result<$elem, crate::util::error::Error> {
|
||||
fn try_from(mut elem: crate::Element) -> Result<$elem, xso::error::FromElementError> {
|
||||
check_self!(elem, $name, $ns);
|
||||
check_no_unknown_attributes!(elem, $name, [$($attr_name),*]);
|
||||
$(
|
||||
|
|
@ -726,14 +726,14 @@ macro_rules! generate_element {
|
|||
let residual = if generate_child_test!(residual, $child_name, $child_ns) {
|
||||
match do_parse_elem!($child_ident: $coucou = $child_constructor => residual, $child_name, $name) {
|
||||
Ok(()) => continue,
|
||||
Err(other) => return Err(other),
|
||||
Err(other) => return Err(other.into()),
|
||||
}
|
||||
} else {
|
||||
residual
|
||||
};
|
||||
)*
|
||||
let _ = residual;
|
||||
return Err(crate::util::error::Error::ParseError(concat!("Unknown child in ", $name, " element.")));
|
||||
return Err(xso::error::Error::Other(concat!("Unknown child in ", $name, " element.")).into());
|
||||
}
|
||||
Ok($elem {
|
||||
$(
|
||||
|
|
@ -787,17 +787,15 @@ macro_rules! assert_size (
|
|||
macro_rules! impl_pubsub_item {
|
||||
($item:ident, $ns:ident) => {
|
||||
impl ::std::convert::TryFrom<crate::Element> for $item {
|
||||
type Error = Error;
|
||||
type Error = FromElementError;
|
||||
|
||||
fn try_from(mut elem: crate::Element) -> Result<$item, Error> {
|
||||
fn try_from(mut elem: crate::Element) -> Result<$item, FromElementError> {
|
||||
check_self!(elem, "item", $ns);
|
||||
check_no_unknown_attributes!(elem, "item", ["id", "publisher"]);
|
||||
let mut payloads = elem.take_contents_as_children().collect::<Vec<_>>();
|
||||
let payload = payloads.pop();
|
||||
if !payloads.is_empty() {
|
||||
return Err(Error::ParseError(
|
||||
"More than a single payload in item element.",
|
||||
));
|
||||
return Err(Error::Other("More than a single payload in item element.").into());
|
||||
}
|
||||
Ok($item(crate::pubsub::Item {
|
||||
id: get_attr!(elem, "id", Option),
|
||||
|
|
|
|||
|
|
@ -4,9 +4,6 @@
|
|||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
/// Error type returned by every parser on failure.
|
||||
pub mod error;
|
||||
|
||||
/// Various helpers.
|
||||
pub(crate) mod text_node_codecs;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@
|
|||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
use crate::util::error::Error;
|
||||
use base64::{engine::general_purpose::STANDARD as Base64Engine, Engine};
|
||||
use jid::Jid;
|
||||
use std::str::FromStr;
|
||||
use xso::error::Error;
|
||||
|
||||
/// A trait for codecs that can decode and encode text nodes.
|
||||
pub trait Codec {
|
||||
|
|
@ -70,7 +70,7 @@ where
|
|||
match s.trim() {
|
||||
// TODO: This error message can be a bit opaque when used
|
||||
// in-context; ideally it'd be configurable.
|
||||
"" => Err(Error::ParseError(
|
||||
"" => Err(Error::Other(
|
||||
"The text in the element's text node was empty after trimming.",
|
||||
)),
|
||||
trimmed => T::decode(trimmed),
|
||||
|
|
@ -89,7 +89,7 @@ impl Codec for Base64 {
|
|||
type Decoded = Vec<u8>;
|
||||
|
||||
fn decode(s: &str) -> Result<Vec<u8>, Error> {
|
||||
Ok(Base64Engine.decode(s)?)
|
||||
Base64Engine.decode(s).map_err(Error::text_parse_error)
|
||||
}
|
||||
|
||||
fn encode(decoded: &Vec<u8>) -> Option<String> {
|
||||
|
|
@ -109,7 +109,7 @@ impl Codec for WhitespaceAwareBase64 {
|
|||
.filter(|ch| *ch != ' ' && *ch != '\n' && *ch != '\t')
|
||||
.collect();
|
||||
|
||||
Ok(Base64Engine.decode(s)?)
|
||||
Base64Engine.decode(s).map_err(Error::text_parse_error)
|
||||
}
|
||||
|
||||
fn encode(decoded: &Self::Decoded) -> Option<String> {
|
||||
|
|
@ -125,12 +125,13 @@ impl<const N: usize> Codec for FixedHex<N> {
|
|||
|
||||
fn decode(s: &str) -> Result<Self::Decoded, Error> {
|
||||
if s.len() != 2 * N {
|
||||
return Err(Error::ParseError("Invalid length"));
|
||||
return Err(Error::Other("Invalid length"));
|
||||
}
|
||||
|
||||
let mut bytes = [0u8; N];
|
||||
for i in 0..N {
|
||||
bytes[i] = u8::from_str_radix(&s[2 * i..2 * i + 2], 16)?;
|
||||
bytes[i] =
|
||||
u8::from_str_radix(&s[2 * i..2 * i + 2], 16).map_err(Error::text_parse_error)?;
|
||||
}
|
||||
|
||||
Ok(bytes)
|
||||
|
|
@ -154,7 +155,8 @@ impl Codec for ColonSeparatedHex {
|
|||
fn decode(s: &str) -> Result<Self::Decoded, Error> {
|
||||
let mut bytes = vec![];
|
||||
for i in 0..(1 + s.len()) / 3 {
|
||||
let byte = u8::from_str_radix(&s[3 * i..3 * i + 2], 16)?;
|
||||
let byte =
|
||||
u8::from_str_radix(&s[3 * i..3 * i + 2], 16).map_err(Error::text_parse_error)?;
|
||||
if 3 * i + 2 < s.len() {
|
||||
assert_eq!(&s[3 * i + 2..3 * i + 3], ":");
|
||||
}
|
||||
|
|
@ -179,7 +181,7 @@ impl Codec for JidCodec {
|
|||
type Decoded = Jid;
|
||||
|
||||
fn decode(s: &str) -> Result<Jid, Error> {
|
||||
Ok(Jid::from_str(s)?)
|
||||
Jid::from_str(s).map_err(Error::text_parse_error)
|
||||
}
|
||||
|
||||
fn encode(jid: &Jid) -> Option<String> {
|
||||
|
|
@ -205,28 +207,28 @@ mod tests {
|
|||
|
||||
// What if we give it a string that's too long?
|
||||
let err = FixedHex::<3>::decode("01feEF01").unwrap_err();
|
||||
assert_eq!(err.to_string(), "parse error: Invalid length");
|
||||
assert_eq!(err.to_string(), "Invalid length");
|
||||
|
||||
// Too short?
|
||||
let err = FixedHex::<3>::decode("01fe").unwrap_err();
|
||||
assert_eq!(err.to_string(), "parse error: Invalid length");
|
||||
assert_eq!(err.to_string(), "Invalid length");
|
||||
|
||||
// Not-even numbers?
|
||||
let err = FixedHex::<3>::decode("01feE").unwrap_err();
|
||||
assert_eq!(err.to_string(), "parse error: Invalid length");
|
||||
assert_eq!(err.to_string(), "Invalid length");
|
||||
|
||||
// No colon supported.
|
||||
let err = FixedHex::<3>::decode("0:f:EF").unwrap_err();
|
||||
assert_eq!(
|
||||
err.to_string(),
|
||||
"integer parsing error: invalid digit found in string"
|
||||
"text parse error: invalid digit found in string"
|
||||
);
|
||||
|
||||
// No non-hex character allowed.
|
||||
let err = FixedHex::<3>::decode("01defg").unwrap_err();
|
||||
assert_eq!(
|
||||
err.to_string(),
|
||||
"integer parsing error: invalid digit found in string"
|
||||
"text parse error: invalid digit found in string"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue