forked from lavina/lavina
1
0
Fork 0
lavina/src/util/xml.rs

81 lines
2.3 KiB
Rust
Raw Normal View History

2023-03-07 13:56:31 +00:00
use quick_xml::events::Event;
2023-03-11 15:07:02 +00:00
use quick_xml::name::ResolveResult;
2023-03-07 13:56:31 +00:00
2023-03-08 18:56:53 +00:00
use crate::prelude::Result;
mod ignore;
pub use ignore::Ignore;
2023-03-08 18:56:53 +00:00
pub trait FromXml: Sized {
type P: Parser<Output = Result<Self>>;
fn parse() -> Self::P;
}
2023-03-12 12:25:23 +00:00
pub trait ToXml: Sized {
fn serialize(&self, events: &mut Vec<Event<'static>>);
}
2023-03-12 13:15:13 +00:00
pub trait FromXmlTag: FromXml {
const NAME: &'static str;
const NS: &'static str;
}
2023-03-07 13:56:31 +00:00
pub trait Parser: Sized {
type Output;
2023-03-11 15:07:02 +00:00
fn consume<'a>(
self: Self,
namespace: ResolveResult,
event: &Event<'a>,
) -> Continuation<Self, Self::Output>;
2023-03-07 13:56:31 +00:00
}
pub enum Continuation<Parser, Res> {
Final(Res),
Continue(Parser),
}
macro_rules! fail_fast {
($errorable: expr) => {
match $errorable {
Ok(i) => i,
Err(e) => return Continuation::Final(Err(e.into())),
2023-03-07 13:56:31 +00:00
}
};
}
2023-03-12 21:50:28 +00:00
macro_rules! delegate_parsing {
($parser: ident, $intermediate: ident, $namespace: expr, $event: expr) => {
match $parser.consume($namespace, $event) {
Continuation::Final(Ok(r)) => Continuation::Final(Ok(r.into())),
Continuation::Final(Err(e)) => Continuation::Final(Err(e)),
Continuation::Continue(s) => {
let inner: $intermediate = s.into();
Continuation::Continue(inner.into())
}
}
};
}
macro_rules! match_parser {
($outer: ident, $name: expr, $ns: expr, $event: expr; $subtype: ty) => {
if $name.0 == <$subtype as FromXmlTag>::NAME.as_bytes() && $ns == ResolveResult::Bound(Namespace(<$subtype as FromXmlTag>::NS.as_bytes())) {
$outer(<$subtype as FromXml>::parse().into()).consume($ns, $event)
} else {
Continuation::Final(Err(ffail!("Unexpected XML event of name {:?} in namespace {:?}", $name, $ns)))
}
};
($outer: ident, $name: expr, $ns: expr, $event: expr; $subtype: ty, $($rest: ty),+) => {
if $name.0 == <$subtype as FromXmlTag>::NAME.as_bytes() && $ns == ResolveResult::Bound(Namespace(<$subtype as FromXmlTag>::NS.as_bytes())) {
$outer(<$subtype as FromXml>::parse().into()).consume($ns, $event)
} else {
match_parser!($outer, $name, $ns, $event; $($rest),*)
}
};
}
pub(crate) use delegate_parsing;
pub(crate) use fail_fast;
2023-03-12 21:50:28 +00:00
pub(crate) use match_parser;