commit 4af66aeaad4f549ccdd872b9978944b693c2d672
parent f214e4c11cfd89f66b4cf68e5f8d29a9c17100af
Author: William Casarin <jb55@jb55.com>
Date: Fri, 26 Apr 2024 23:22:03 -0700
nip10: add owned variants
So that we can store a small amount of data that can construct reply
information.
Signed-off-by: William Casarin <jb55@jb55.com>
Diffstat:
2 files changed, 115 insertions(+), 6 deletions(-)
diff --git a/src/lib.rs b/src/lib.rs
@@ -40,6 +40,6 @@ pub use result::Result;
pub use subscription::Subscription;
pub use tags::{Tag, TagIter, Tags, TagsIter};
pub use transaction::Transaction;
-pub use util::nip10::{Marker, NoteIdRef, NoteReply};
+pub use util::nip10::{Marker, NoteIdRef, NoteIdRefBuf, NoteReply, NoteReplyBuf};
mod test_util;
diff --git a/src/util/nip10.rs b/src/util/nip10.rs
@@ -7,13 +7,89 @@ pub enum Marker {
Mention,
}
+/// Parsed `e` tags
#[derive(Clone, Copy, Debug)]
pub struct NoteIdRef<'a> {
+ pub index: u16,
pub id: &'a [u8; 32],
pub relay: Option<&'a str>,
pub marker: Option<Marker>,
}
+impl<'a> NoteIdRef<'a> {
+ pub fn to_owned(&self) -> NoteIdRefBuf {
+ NoteIdRefBuf {
+ index: self.index,
+ marker: self.marker,
+ }
+ }
+}
+
+pub struct NoteIdRefBuf {
+ pub index: u16,
+ pub marker: Option<Marker>,
+}
+
+impl NoteReplyBuf {
+ // TODO(jb55): optimize this function. It is not the nicest code.
+ // We could simplify the index lookup by offsets into the Note's
+ // string table
+ pub fn borrow<'a>(&self, tags: Tags<'a>) -> NoteReply<'a> {
+ let helper = |tag: Tag<'a>, marker: Option<Marker>, index: i32| {
+ let id = tag
+ .get_unchecked(1)
+ .variant()
+ .id()
+ .expect("expected id at index, do you have the correct note?");
+ let relay = tag.get(2).and_then(|t| t.variant().str());
+ Some(NoteIdRef {
+ index: index as u16,
+ id,
+ relay,
+ marker,
+ })
+ };
+
+ let mut root: Option<NoteIdRef<'a>> = None;
+ let mut reply: Option<NoteIdRef<'a>> = None;
+ let mut mention: Option<NoteIdRef<'a>> = None;
+
+ let mut index: i32 = -1;
+ for tag in tags {
+ index += 1;
+ if tag.count() < 2 && tag.get_unchecked(0).variant().str() != Some("e") {
+ continue;
+ }
+
+ if self
+ .root
+ .as_ref()
+ .map_or(false, |x| x.index == index as u16)
+ {
+ root = helper(tag, self.root.as_ref().unwrap().marker, index)
+ } else if self
+ .reply
+ .as_ref()
+ .map_or(false, |x| x.index == index as u16)
+ {
+ reply = helper(tag, self.reply.as_ref().unwrap().marker, index)
+ } else if self
+ .mention
+ .as_ref()
+ .map_or(false, |x| x.index == index as u16)
+ {
+ mention = helper(tag, self.mention.as_ref().unwrap().marker, index)
+ }
+ }
+
+ NoteReply {
+ root,
+ reply,
+ mention,
+ }
+ }
+}
+
#[derive(Clone, Copy, Debug)]
pub struct NoteReply<'a> {
root: Option<NoteIdRef<'a>>,
@@ -21,6 +97,13 @@ pub struct NoteReply<'a> {
mention: Option<NoteIdRef<'a>>,
}
+/// Owned version of NoteReply, stores tag indices
+pub struct NoteReplyBuf {
+ root: Option<NoteIdRefBuf>,
+ reply: Option<NoteIdRefBuf>,
+ mention: Option<NoteIdRefBuf>,
+}
+
impl<'a> NoteReply<'a> {
pub fn reply_to_root(self) -> Option<NoteIdRef<'a>> {
if self.is_reply_to_root() {
@@ -30,6 +113,14 @@ impl<'a> NoteReply<'a> {
}
}
+ pub fn to_owned(&self) -> NoteReplyBuf {
+ NoteReplyBuf {
+ root: self.root.map(|x| x.to_owned()),
+ reply: self.reply.map(|x| x.to_owned()),
+ mention: self.mention.map(|x| x.to_owned()),
+ }
+ }
+
pub fn new(tags: Tags<'a>) -> NoteReply<'a> {
tags_to_note_reply(tags)
}
@@ -76,13 +167,16 @@ fn tags_to_note_reply<'a>(tags: Tags<'a>) -> NoteReply<'a> {
let mut reply: Option<NoteIdRef<'a>> = None;
let mut mention: Option<NoteIdRef<'a>> = None;
let mut first: bool = true;
+ let mut index: i32 = -1;
for tag in tags {
+ index += 1;
+
if root.is_some() && reply.is_some() && mention.is_some() {
break;
}
- let note_ref = if let Ok(note_ref) = tag_to_noteid_ref(tag) {
+ let note_ref = if let Ok(note_ref) = tag_to_noteid_ref(tag, index as u16) {
note_ref
} else {
continue;
@@ -117,7 +211,7 @@ fn tags_to_note_reply<'a>(tags: Tags<'a>) -> NoteReply<'a> {
}
}
-pub fn tag_to_noteid_ref(tag: Tag<'_>) -> Result<NoteIdRef<'_>, Error> {
+pub fn tag_to_noteid_ref(tag: Tag<'_>, index: u16) -> Result<NoteIdRef<'_>, Error> {
if tag.count() < 2 {
return Err(Error::DecodeError);
}
@@ -132,13 +226,21 @@ pub fn tag_to_noteid_ref(tag: Tag<'_>) -> Result<NoteIdRef<'_>, Error> {
.id()
.ok_or(Error::DecodeError)?;
- let relay = tag.get(2).and_then(|t| t.variant().str());
+ let relay = tag
+ .get(2)
+ .and_then(|t| t.variant().str())
+ .filter(|x| *x != "");
let marker = tag
.get(3)
.and_then(|t| t.variant().str())
.and_then(Marker::new);
- Ok(NoteIdRef { id, relay, marker })
+ Ok(NoteIdRef {
+ index,
+ id,
+ relay,
+ marker,
+ })
}
#[cfg(test)]
@@ -360,11 +462,18 @@ mod test {
assert_eq!(res, vec![NoteKey::new(1)]);
let txn = Transaction::new(&ndb).unwrap();
let res = ndb.query(&txn, vec![filter], 1).expect("note");
- let note_reply = NoteReply::new(res[0].note.tags());
+ let note = &res[0].note;
+ let note_reply = NoteReply::new(note.tags());
assert_eq!(*note_reply.reply_to_root().unwrap().id, root_id);
assert_eq!(*note_reply.reply().unwrap().id, root_id);
assert_eq!(note_reply.mention().is_none(), true);
+
+ // test the to_owned version
+ let back_again = note_reply.to_owned().borrow(note.tags());
+ assert_eq!(*back_again.reply_to_root().unwrap().id, root_id);
+ assert_eq!(*back_again.reply().unwrap().id, root_id);
+ assert_eq!(back_again.mention().is_none(), true);
}
}
}