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 }