nostrdb-rs

nostrdb in rust!
git clone git://jb55.com/nostrdb-rs
Log | Files | Refs | Submodules | README | LICENSE

tags.rs (7554B)


      1 use crate::{bindings, NdbStr, Note};
      2 
      3 #[derive(Debug, Clone)]
      4 pub struct Tag<'n> {
      5     ptr: *mut bindings::ndb_tag,
      6     note: Note<'n>,
      7 }
      8 
      9 impl<'n> Tag<'n> {
     10     pub(crate) fn new(ptr: *mut bindings::ndb_tag, note: Note<'n>) -> Self {
     11         Tag { ptr, note }
     12     }
     13 
     14     pub fn count(&self) -> u16 {
     15         unsafe { bindings::ndb_tag_count(self.as_ptr()) }
     16     }
     17 
     18     pub fn get_unchecked(&self, ind: u16) -> NdbStr<'n> {
     19         let nstr = unsafe {
     20             bindings::ndb_tag_str(
     21                 self.note().as_ptr(),
     22                 self.as_ptr(),
     23                 ind as ::std::os::raw::c_int,
     24             )
     25         };
     26         NdbStr::new(nstr, self.note.clone())
     27     }
     28 
     29     pub fn get_str(&self, ind: u16) -> Option<&'n str> {
     30         self.get(ind).and_then(|s| s.str())
     31     }
     32 
     33     pub fn get_id(&self, ind: u16) -> Option<&'n [u8; 32]> {
     34         self.get(ind).and_then(|s| s.id())
     35     }
     36 
     37     pub fn get(&self, ind: u16) -> Option<NdbStr<'n>> {
     38         if ind >= self.count() {
     39             return None;
     40         }
     41         Some(self.get_unchecked(ind))
     42     }
     43 
     44     pub fn note(&self) -> &Note<'n> {
     45         &self.note
     46     }
     47 
     48     pub fn as_ptr(&self) -> *mut bindings::ndb_tag {
     49         self.ptr
     50     }
     51 }
     52 
     53 impl<'a> IntoIterator for Tag<'a> {
     54     type Item = NdbStr<'a>;
     55     type IntoIter = TagIter<'a>;
     56 
     57     fn into_iter(self) -> Self::IntoIter {
     58         TagIter::new(self)
     59     }
     60 }
     61 
     62 #[derive(Debug, Clone)]
     63 pub struct Tags<'a> {
     64     ptr: *mut bindings::ndb_tags,
     65     note: Note<'a>,
     66 }
     67 
     68 impl<'a> IntoIterator for Tags<'a> {
     69     type Item = Tag<'a>;
     70     type IntoIter = TagsIter<'a>;
     71 
     72     fn into_iter(self) -> TagsIter<'a> {
     73         TagsIter::new(self.note().clone())
     74     }
     75 }
     76 
     77 impl<'a> Tags<'a> {
     78     pub(crate) fn new(ptr: *mut bindings::ndb_tags, note: Note<'a>) -> Self {
     79         Tags { ptr, note }
     80     }
     81 
     82     pub fn count(&self) -> u16 {
     83         unsafe { bindings::ndb_tags_count(self.as_ptr()) }
     84     }
     85 
     86     pub fn iter(&self) -> TagsIter<'a> {
     87         TagsIter::new(self.note.clone())
     88     }
     89 
     90     pub fn note(&self) -> &Note<'a> {
     91         &self.note
     92     }
     93 
     94     pub fn as_ptr(&self) -> *mut bindings::ndb_tags {
     95         self.ptr
     96     }
     97 }
     98 
     99 #[derive(Debug, Clone)]
    100 pub struct TagsIter<'a> {
    101     iter: bindings::ndb_iterator,
    102     note: Note<'a>,
    103 }
    104 
    105 impl<'a> TagsIter<'a> {
    106     pub fn new(note: Note<'a>) -> Self {
    107         let iter = bindings::ndb_iterator {
    108             note: std::ptr::null_mut(),
    109             tag: std::ptr::null_mut(),
    110             index: 0,
    111         };
    112         let mut iter = TagsIter { note, iter };
    113         unsafe {
    114             bindings::ndb_tags_iterate_start(iter.note.as_ptr(), &mut iter.iter);
    115         };
    116         iter
    117     }
    118 
    119     pub fn tag(&self) -> Option<Tag<'a>> {
    120         let tag_ptr = unsafe { *self.as_ptr() }.tag;
    121         if tag_ptr.is_null() {
    122             None
    123         } else {
    124             Some(Tag::new(tag_ptr, self.note().clone()))
    125         }
    126     }
    127 
    128     pub fn note(&self) -> &Note<'a> {
    129         &self.note
    130     }
    131 
    132     pub fn as_ptr(&self) -> *const bindings::ndb_iterator {
    133         &self.iter
    134     }
    135 
    136     pub fn as_mut_ptr(&mut self) -> *mut bindings::ndb_iterator {
    137         &mut self.iter
    138     }
    139 }
    140 
    141 #[derive(Debug, Clone)]
    142 pub struct TagIter<'a> {
    143     tag: Tag<'a>,
    144     index: u16,
    145 }
    146 
    147 impl<'a> TagIter<'a> {
    148     pub fn new(tag: Tag<'a>) -> Self {
    149         let index = 0;
    150         TagIter { tag, index }
    151     }
    152 
    153     pub fn done(&self) -> bool {
    154         self.index >= self.tag.count()
    155     }
    156 }
    157 
    158 impl<'a> Iterator for TagIter<'a> {
    159     type Item = NdbStr<'a>;
    160 
    161     fn next(&mut self) -> Option<NdbStr<'a>> {
    162         let tag = self.tag.get(self.index);
    163         if tag.is_some() {
    164             self.index += 1;
    165             tag
    166         } else {
    167             None
    168         }
    169     }
    170 }
    171 
    172 impl<'a> Iterator for TagsIter<'a> {
    173     type Item = Tag<'a>;
    174 
    175     fn next(&mut self) -> Option<Self::Item> {
    176         let res = unsafe { bindings::ndb_tags_iterate_next(self.as_mut_ptr()) };
    177         if res == 0 {
    178             None
    179         } else {
    180             self.tag()
    181         }
    182     }
    183 }
    184 
    185 #[cfg(test)]
    186 mod tests {
    187     use crate::config::Config;
    188     use crate::test_util;
    189     use crate::{Filter, Ndb, NdbStrVariant, Transaction};
    190 
    191     #[tokio::test]
    192     async fn tag_iter_works() {
    193         let db = "target/testdbs/tag_iter_works";
    194         test_util::cleanup_db(&db);
    195 
    196         {
    197             let ndb = Ndb::new(db, &Config::new()).expect("ndb");
    198             let sub = ndb
    199                 .subscribe(&[Filter::new()
    200                     .ids([&[
    201                         0xc5, 0xd9, 0x8c, 0xbf, 0x4b, 0xcd, 0x81, 0x1e, 0x28, 0x66, 0x77, 0x0c,
    202                         0x3d, 0x38, 0x0c, 0x02, 0x84, 0xce, 0x1d, 0xaf, 0x3a, 0xe9, 0x98, 0x3d,
    203                         0x22, 0x56, 0x5c, 0xb0, 0x66, 0xcf, 0x2a, 0x19,
    204                     ]])
    205                     .build()])
    206                 .expect("sub");
    207             let waiter = ndb.wait_for_notes(sub, 1);
    208             ndb.process_event(r#"["EVENT","s",{"id": "c5d98cbf4bcd811e2866770c3d380c0284ce1daf3ae9983d22565cb066cf2a19","pubkey": "083727b7a6051673f399102dc48c229c0ec08186ecd7e54ad0e9116d38429c4f","created_at": 1712517119,"kind": 1,"tags": [["e","b9e548b4aa30fa4ce9edf552adaf458385716704994fbaa9e0aa0042a5a5e01e"],["p","140ee9ff21da6e6671f750a0a747c5a3487ee8835159c7ca863e867a1c537b4f"],["hi","3"]],"content": "hi","sig": "1eed792e4db69c2bde2f5be33a383ef8b17c6afd1411598d0c4618fbdf4dbcb9689354276a74614511907a45eec234e0786733e8a6fbb312e6abf153f15fd437"}]"#).expect("process ok");
    209             let res = waiter.await.expect("await ok");
    210             assert_eq!(res.len(), 1);
    211             let note_key = res[0];
    212             let txn = Transaction::new(&ndb).expect("txn");
    213             let note = ndb.get_note_by_key(&txn, note_key).expect("note");
    214             let tags = note.tags();
    215             assert_eq!(tags.count(), 3);
    216 
    217             let mut tags_iter = tags.iter();
    218 
    219             let t0 = tags_iter.next().expect("t0");
    220             let t0_e0 = t0.get(0).expect("e tag ok");
    221             let t0_e1 = t0.get(1).expect("e id ok");
    222             assert_eq!(t0.get(2).is_none(), true);
    223             assert_eq!(t0_e0.variant(), NdbStrVariant::Str("e"));
    224             assert_eq!(
    225                 t0_e1.variant(),
    226                 NdbStrVariant::Id(&[
    227                     0xb9, 0xe5, 0x48, 0xb4, 0xaa, 0x30, 0xfa, 0x4c, 0xe9, 0xed, 0xf5, 0x52, 0xad,
    228                     0xaf, 0x45, 0x83, 0x85, 0x71, 0x67, 0x04, 0x99, 0x4f, 0xba, 0xa9, 0xe0, 0xaa,
    229                     0x00, 0x42, 0xa5, 0xa5, 0xe0, 0x1e
    230                 ])
    231             );
    232 
    233             let t1 = tags_iter.next().expect("t1");
    234             let t1_e0 = t1.get(0).expect("p tag ok");
    235             let t1_e1 = t1.get(1).expect("p id ok");
    236             assert_eq!(t1.get(2).is_none(), true);
    237             assert_eq!(t1_e0.variant(), NdbStrVariant::Str("p"));
    238             assert_eq!(
    239                 t1_e1.variant(),
    240                 NdbStrVariant::Id(&[
    241                     0x14, 0x0e, 0xe9, 0xff, 0x21, 0xda, 0x6e, 0x66, 0x71, 0xf7, 0x50, 0xa0, 0xa7,
    242                     0x47, 0xc5, 0xa3, 0x48, 0x7e, 0xe8, 0x83, 0x51, 0x59, 0xc7, 0xca, 0x86, 0x3e,
    243                     0x86, 0x7a, 0x1c, 0x53, 0x7b, 0x4f
    244                 ])
    245             );
    246 
    247             let t2 = tags_iter.next().expect("t2");
    248             let t2_e0 = t2.get(0).expect("hi tag ok");
    249             let t2_e1 = t2.get(1).expect("hi value ok");
    250             assert_eq!(t2.get(2).is_none(), true);
    251             assert_eq!(t2_e0.variant(), NdbStrVariant::Str("hi"));
    252             assert_eq!(t2_e1.variant(), NdbStrVariant::Str("3"));
    253 
    254             assert_eq!(tags_iter.next().is_none(), true);
    255         }
    256     }
    257 }