nostrdb-rs

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

tags.rs (7338B)


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