damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

NdbTagsIterator.swift (2070B)


      1 //
      2 //  NdbTagsIterator.swift
      3 //  damus
      4 //
      5 //  Created by William Casarin on 2023-07-21.
      6 //
      7 
      8 import Foundation
      9 
     10 struct TagsIterator: IteratorProtocol {
     11     typealias Element = TagSequence
     12 
     13     var done: Bool
     14     var iter: ndb_iterator
     15     var note: NdbNote
     16 
     17     mutating func next() -> TagSequence? {
     18         guard ndb_tags_iterate_next(&self.iter) == 1 else {
     19             done = true
     20             return nil
     21         }
     22 
     23         let tag_ptr = ndb_tag_ptr(ptr: self.iter.tag)
     24         return TagSequence(note: note, tag: tag_ptr)
     25     }
     26 
     27     init(note: NdbNote) {
     28         self.iter = ndb_iterator()
     29         ndb_tags_iterate_start(note.note.ptr, &self.iter)
     30         self.done = false
     31         self.note = note
     32     }
     33 }
     34 
     35 struct TagsSequence: Encodable, Sequence {
     36     let note: NdbNote
     37 
     38     var count: UInt16 {
     39         let tags_ptr = ndb_note_tags(note.note.ptr)
     40         return ndb_tags_count(tags_ptr)
     41     }
     42 
     43     func strings() -> [[String]] {
     44         return self.map { tag in
     45             tag.map { t in t.string() }
     46         }
     47     }
     48 
     49     func encode(to encoder: Encoder) throws {
     50         var container = encoder.unkeyedContainer()
     51         
     52         // Iterate and create the [[String]] for encoding
     53         for tag in self {
     54             try container.encode(tag.map { $0.string() })
     55         }
     56     }
     57 
     58     // no O(1) indexing on top-level tag lists unfortunately :(
     59     // bit it's very fast to iterate over each tag since the number of tags
     60     // are stored and the elements are fixed size.
     61     subscript(index: Int) -> Iterator.Element {
     62         var i = 0
     63         for element in self {
     64             if i == index {
     65                 return element
     66             }
     67             i += 1
     68         }
     69         precondition(false, "Sequence subscript out of bounds")
     70         // it seems like the compiler needs this or it gets bitchy
     71         let nil_ptr = OpaquePointer(bitPattern: 0)
     72         return .init(note: .init(note: .init(ptr: nil_ptr), size: 0, owned: true, key: nil), tag: .init(ptr: nil_ptr))
     73     }
     74 
     75     func makeIterator() -> TagsIterator {
     76         return .init(note: note)
     77     }
     78 }