tags.rs (7341B)
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(&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(&self) -> &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: 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().clone()) 66 } 67 } 68 69 impl<'a> Tags<'a> { 70 pub(crate) fn new(ptr: *mut bindings::ndb_tags, note: 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.clone()) 80 } 81 82 pub fn note(&self) -> &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: Note<'a>, 95 } 96 97 impl<'a> TagsIter<'a> { 98 pub fn new(note: 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(iter.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().clone())) 117 } 118 } 119 120 pub fn note(&self) -> &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([&[ 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.id, 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 }