rewrite presence parser as a generator

This commit is contained in:
Nikita Vilunov 2023-03-23 02:20:30 +01:00
parent d0f807841c
commit 9110ab9beb
1 changed files with 66 additions and 123 deletions

View File

@ -402,132 +402,75 @@ impl PresenceShow {
}
}
#[derive(From)]
pub struct PresenceParser<T: FromXml>(PresenceParserInner<T>);
enum PresenceParserInner<T: FromXml> {
Initial,
InPresence(Presence<T>),
InPriority(Presence<T>),
InPriorityEnd(Presence<T>),
InShow(Presence<T>),
InShowEnd(Presence<T>),
InStatus(Presence<T>),
InStatusEnd(Presence<T>),
InCustom(Presence<T>, T::P),
}
impl<T: FromXml> Parser for PresenceParser<T> {
type Output = Result<Presence<T>>;
fn consume<'a>(
self: Self,
namespace: ResolveResult,
event: &Event<'a>,
) -> Continuation<Self, Self::Output> {
match self.0 {
PresenceParserInner::Initial => match event {
//TODO validate
Event::Start(bytes) => Continuation::Continue(
PresenceParserInner::InPresence(Presence::default()).into(),
),
Event::Empty(bytes) => Continuation::Final(Ok(Presence::default())),
_ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))),
},
PresenceParserInner::InPresence(p) => match event {
Event::Start(bytes) => match bytes.name().0 {
b"show" => Continuation::Continue(PresenceParserInner::InShow(p).into()),
b"status" => Continuation::Continue(PresenceParserInner::InStatus(p).into()),
b"priority" => {
Continuation::Continue(PresenceParserInner::InPriority(p).into())
}
_ => PresenceParser(PresenceParserInner::InCustom(p, T::parse()))
.consume(namespace, event),
},
Event::Empty(_) => PresenceParser(PresenceParserInner::InCustom(p, T::parse()))
.consume(namespace, event),
Event::End(_) => Continuation::Final(Ok(p)),
_ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))),
},
PresenceParserInner::InPriority(p) => match event {
Event::Text(bytes) => {
match (|| {
let s = std::str::from_utf8(bytes)?;
let i = s.parse()?;
Ok(Presence {
priority: Some(PresencePriority(i)),
..p
})
})() {
Ok(res) => {
Continuation::Continue(PresenceParserInner::InPriorityEnd(res).into())
}
Err(e) => Continuation::Final(Err(e)),
}
}
_ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))),
},
PresenceParserInner::InPriorityEnd(p) => match event {
Event::End(_) => Continuation::Continue(PresenceParserInner::InPresence(p).into()),
_ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))),
},
PresenceParserInner::InShow(p) => match event {
Event::Text(bytes) => {
match (|| {
let i = PresenceShow::from_str(bytes)?;
Ok(Presence { show: Some(i), ..p })
})() {
Ok(res) => {
Continuation::Continue(PresenceParserInner::InShowEnd(res).into())
}
Err(e) => Continuation::Final(Err(e)),
}
}
_ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))),
},
PresenceParserInner::InShowEnd(p) => match event {
Event::End(_) => Continuation::Continue(PresenceParserInner::InPresence(p).into()),
_ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))),
},
PresenceParserInner::InStatus(mut p) => match event {
Event::Text(bytes) => {
match (|| {
let i = std::str::from_utf8(bytes)?;
p.status.push(i.to_string());
Ok(p)
})() {
Ok(res) => {
Continuation::Continue(PresenceParserInner::InStatusEnd(res).into())
}
Err(e) => Continuation::Final(Err(e)),
}
}
_ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))),
},
PresenceParserInner::InStatusEnd(p) => match event {
Event::End(_) => Continuation::Continue(PresenceParserInner::InPresence(p).into()),
_ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))),
},
PresenceParserInner::InCustom(mut p, c) => match c.consume(namespace, event) {
Continuation::Final(Ok(res)) => {
p.custom.push(res);
Continuation::Continue(PresenceParserInner::InPresence(p).into())
}
Continuation::Final(Err(err)) => Continuation::Final(Err(ffail!(
"Failed to parse custom presence element: {err}"
))),
Continuation::Continue(c) => {
Continuation::Continue(PresenceParserInner::InCustom(p, c).into())
}
},
}
}
}
impl<T: FromXml> FromXml for Presence<T> {
type P = PresenceParser<T>;
type P = impl Parser<Output = Result<Presence<T>>>;
fn parse() -> Self::P {
PresenceParserInner::Initial.into()
|(namespace, event): (ResolveResult<'static>, &'static Event<'static>)| -> Result<Self> {
let _ = match event {
Event::Start(bytes) => bytes,
Event::Empty(_) => return Ok(Presence::default()),
_ => return Err(ffail!("Unexpected XML event: {event:?}")),
};
let mut p = Presence::<T>::default();
loop {
let (namespace, event) = yield;
match event {
Event::Start(bytes) => match bytes.name().0 {
b"show" => {
let (_, event) = yield;
let Event::Text(bytes) = event else {
return Err(ffail!("Unexpected XML event: {event:?}"));
};
let i = PresenceShow::from_str(bytes)?;
p.show = Some(i);
let (_, event) = yield;
let Event::End(_) = event else {
return Err(ffail!("Unexpected XML event: {event:?}"));
};
}
b"status" => {
let (_, event) = yield;
let Event::Text(bytes) = event else {
return Err(ffail!("Unexpected XML event: {event:?}"));
};
let s = std::str::from_utf8(bytes)?;
p.status.push(s.to_string());
let (_, event) = yield;
let Event::End(_) = event else {
return Err(ffail!("Unexpected XML event: {event:?}"));
};
}
b"priority" => {
let (_, event) = yield;
let Event::Text(bytes) = event else {
return Err(ffail!("Unexpected XML event: {event:?}"));
};
let s = std::str::from_utf8(bytes)?;
let i = s.parse()?;
p.priority = Some(PresencePriority(i));
let (_, event) = yield;
let Event::End(_) = event else {
return Err(ffail!("Unexpected XML event: {event:?}"));
};
}
_ => {
let res = delegate_parsing!(T, namespace, event);
p.custom.push(res?);
}
},
Event::Empty(_) => {
let res = delegate_parsing!(T, namespace, event);
p.custom.push(res?);
}
Event::End(_) => return Ok(p),
_ => return Err(ffail!("Unexpected XML event: {event:?}")),
}
}
}
}
}