token_parser: unify parsing and serialization

This reduces the number of things we have to update in our token parser
and serializer. For payloads, we we have to handle the payload cases
different, but we now have a structure that can deal with that
efficiently.

Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
William Casarin
2025-01-05 10:57:37 -06:00
parent 005ecd740d
commit 61b3a92792
2 changed files with 48 additions and 43 deletions

View File

@@ -146,6 +146,7 @@ pub trait TokenSerializable: Sized {
/// Return a list of serialization plans for a type. We do this for
/// type safety and assume constructing these types are lightweight
fn parse<'a>(parser: &mut TokenParser<'a>) -> Result<Self, ParseError<'a>>;
fn serialize(&self, write_token: fn(&str) -> Result<(), std::io::Error>) -> Result<(), std::io::Error>;
}
#[cfg(test)]

View File

@@ -80,7 +80,47 @@ pub enum AddColumnRoute {
ExternalIndividual,
}
// Parser for the common case without any payloads
fn parse_column_route<'a>(
parser: &mut TokenParser<'a>,
route: AddColumnRoute,
) -> Result<AddColumnRoute, ParseError<'a>> {
parser.parse_all(|p| {
for token in route.tokens() {
p.parse_token(token)?;
}
Ok(route)
})
}
impl AddColumnRoute {
/// Route tokens use in both serialization and deserialization
fn tokens(&self) -> &'static [&'static str] {
match self {
Self::Base => &[],
Self::UndecidedNotification => &["notification_selection"],
Self::ExternalNotification => &["external_notif_selection"],
Self::UndecidedIndividual => &["individual_selection"],
Self::ExternalIndividual => &["external_individual_selection"],
Self::Hashtag => &["hashtag"],
Self::Algo(AddAlgoRoute::Base) => &["algo_selection"],
Self::Algo(AddAlgoRoute::LastPerPubkey) => &["algo_selection", "last_per_pubkey"],
// NOTE!!! When adding to this, update the parser for TokenSerializable below
}
}
}
impl TokenSerializable for AddColumnRoute {
fn serialize(
&self,
write_token: fn(&str) -> Result<(), std::io::Error>,
) -> Result<(), std::io::Error> {
for token in self.tokens() {
write_token(token)?;
}
Ok(())
}
fn parse<'a>(parser: &mut TokenParser<'a>) -> Result<Self, ParseError<'a>> {
// all start with column
parser.parse_token("column")?;
@@ -93,49 +133,13 @@ impl TokenSerializable for AddColumnRoute {
TokenParser::alt(
parser,
&[
|p| {
p.parse_all(|p| {
p.parse_token("external_notif_selection")?;
Ok(AddColumnRoute::UndecidedNotification)
})
},
|p| {
p.parse_all(|p| {
p.parse_token("external_notif_selection")?;
Ok(AddColumnRoute::ExternalNotification)
})
},
|p| {
p.parse_all(|p| {
p.parse_token("hashtag_selection")?;
Ok(AddColumnRoute::Hashtag)
})
},
|p| {
p.parse_all(|p| {
p.parse_token("algo_selection")?;
Ok(AddColumnRoute::Algo(AddAlgoRoute::Base))
})
},
|p| {
p.parse_all(|p| {
p.parse_token("algo_selection")?;
p.parse_token("last_per_pubkey")?;
Ok(AddColumnRoute::Algo(AddAlgoRoute::LastPerPubkey))
})
},
|p| {
p.parse_all(|p| {
p.parse_token("individual_selection")?;
Ok(AddColumnRoute::UndecidedIndividual)
})
},
|p| {
p.parse_all(|p| {
p.parse_token("external_individual_selection")?;
Ok(AddColumnRoute::ExternalIndividual)
})
},
|p| parse_column_route(p, AddColumnRoute::UndecidedNotification),
|p| parse_column_route(p, AddColumnRoute::ExternalNotification),
|p| parse_column_route(p, AddColumnRoute::UndecidedIndividual),
|p| parse_column_route(p, AddColumnRoute::ExternalIndividual),
|p| parse_column_route(p, AddColumnRoute::Hashtag),
|p| parse_column_route(p, AddColumnRoute::Algo(AddAlgoRoute::Base)),
|p| parse_column_route(p, AddColumnRoute::Algo(AddAlgoRoute::LastPerPubkey)),
],
)
}