From 4e87ed7065c4de0e5fd8791db9e6a6a094fea6a5 Mon Sep 17 00:00:00 2001 From: William Casarin Date: Tue, 21 Jan 2025 13:13:28 -0800 Subject: [PATCH] tokens: add TimelineRoute token serializer Signed-off-by: William Casarin --- crates/notedeck_columns/src/timeline/mod.rs | 2 +- crates/notedeck_columns/src/timeline/route.rs | 87 +++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/crates/notedeck_columns/src/timeline/mod.rs b/crates/notedeck_columns/src/timeline/mod.rs index 8fc81e6a..85a0c446 100644 --- a/crates/notedeck_columns/src/timeline/mod.rs +++ b/crates/notedeck_columns/src/timeline/mod.rs @@ -30,7 +30,7 @@ pub mod kind; pub mod route; pub use cache::{TimelineCache, TimelineCacheKey}; -pub use kind::{AlgoTimeline, ColumnTitle, PubkeySource, TimelineKind}; +pub use kind::{ColumnTitle, PubkeySource, TimelineKind}; pub use route::TimelineRoute; #[derive(Debug, Hash, Copy, Clone, Eq, PartialEq)] diff --git a/crates/notedeck_columns/src/timeline/route.rs b/crates/notedeck_columns/src/timeline/route.rs index 4e8b9220..7a0effc4 100644 --- a/crates/notedeck_columns/src/timeline/route.rs +++ b/crates/notedeck_columns/src/timeline/route.rs @@ -3,6 +3,7 @@ use crate::{ draft::Drafts, nav::RenderNavAction, profile::ProfileAction, + storage::{ParseError, Payload, Token, TokenParser, TokenSerializable, TokenWriter}, timeline::{TimelineCache, TimelineId, TimelineKind}, ui::{ self, @@ -24,6 +25,67 @@ pub enum TimelineRoute { Quote(NoteId), } +const PROFILE_TOKENS: &[Token] = &[Token::id("profile"), Token::pubkey()]; +const THREAD_TOKENS: &[Token] = &[Token::id("thread"), Token::note_id()]; +const REPLY_TOKENS: &[Token] = &[Token::id("reply"), Token::note_id()]; +const QUOTE_TOKENS: &[Token] = &[Token::id("quote"), Token::note_id()]; + +impl TimelineRoute { + fn payload(&self) -> Option { + match self { + TimelineRoute::Profile(pk) => Some(Payload::pubkey(*pk)), + TimelineRoute::Thread(note_id) => Some(Payload::note_id(*note_id)), + TimelineRoute::Reply(note_id) => Some(Payload::note_id(*note_id)), + TimelineRoute::Quote(note_id) => Some(Payload::note_id(*note_id)), + TimelineRoute::Timeline(_timeline_id) => todo!("handle timeline_ids"), + } + } + + fn tokens(&self) -> &'static [Token] { + match self { + TimelineRoute::Profile(_) => PROFILE_TOKENS, + TimelineRoute::Thread(_) => THREAD_TOKENS, + TimelineRoute::Reply(_) => REPLY_TOKENS, + TimelineRoute::Quote(_) => QUOTE_TOKENS, + TimelineRoute::Timeline(_) => todo!("handle timeline_ids"), + } + } + + /// NOTE!! update parse_from_tokens as well when adding to this match + fn parse<'a>(&self, parser: &mut TokenParser<'a>) -> Result> { + let payload = Token::parse_all(parser, self.tokens())?; + + match self { + TimelineRoute::Profile(_) => { + Ok(TimelineRoute::Profile(Payload::parse_pubkey(payload)?)) + } + TimelineRoute::Thread(_) => Ok(TimelineRoute::Thread(Payload::parse_note_id(payload)?)), + TimelineRoute::Reply(_) => Ok(TimelineRoute::Reply(Payload::parse_note_id(payload)?)), + TimelineRoute::Quote(_) => Ok(TimelineRoute::Quote(Payload::parse_note_id(payload)?)), + TimelineRoute::Timeline(_) => todo!("handle timeline parsing"), + } + } +} + +impl TokenSerializable for TimelineRoute { + fn serialize_tokens(&self, writer: &mut TokenWriter) { + Token::serialize_all(writer, self.tokens(), self.payload().as_ref()); + } + + fn parse_from_tokens<'a>(parser: &mut TokenParser<'a>) -> Result> { + TokenParser::alt( + parser, + &[ + |p| TimelineRoute::Profile(Pubkey::new([0; 32])).parse(p), + |p| TimelineRoute::Thread(NoteId::new([0; 32])).parse(p), + |p| TimelineRoute::Reply(NoteId::new([0; 32])).parse(p), + |p| TimelineRoute::Quote(NoteId::new([0; 32])).parse(p), + |_p| todo!("handle timeline parsing"), + ], + ) + } +} + #[allow(clippy::too_many_arguments)] pub fn render_timeline_route( ndb: &Ndb, @@ -193,3 +255,28 @@ pub fn render_profile_route( None } } + +#[cfg(test)] +mod tests { + use crate::storage::{TokenParser, TokenSerializable, TokenWriter}; + use enostr::NoteId; + + #[test] + fn test_timeline_route_serialize() { + use super::TimelineRoute; + + { + let note_id_hex = "1c54e5b0c386425f7e017d9e068ddef8962eb2ce1bb08ed27e24b93411c12e60"; + let note_id = NoteId::from_hex(note_id_hex).unwrap(); + let data_str = format!("thread:{}", note_id_hex); + let data = &data_str.split(":").collect::>(); + let mut token_writer = TokenWriter::default(); + let mut parser = TokenParser::new(&data); + let parsed = TimelineRoute::parse_from_tokens(&mut parser).unwrap(); + let expected = TimelineRoute::Thread(note_id); + parsed.serialize_tokens(&mut token_writer); + assert_eq!(expected, parsed); + assert_eq!(token_writer.str(), data_str); + } + } +}