forked from lavina/lavina
rewrite presence parser as a generator
This commit is contained in:
parent
d0f807841c
commit
9110ab9beb
|
@ -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> {
|
impl<T: FromXml> FromXml for Presence<T> {
|
||||||
type P = PresenceParser<T>;
|
type P = impl Parser<Output = Result<Presence<T>>>;
|
||||||
|
|
||||||
fn parse() -> Self::P {
|
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:?}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue