NdbTagsIterator.swift (1983B)
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 return TagSequence(note: note, tag: self.iter.tag) 24 } 25 26 var count: UInt16 { 27 return note.note.pointee.tags.count 28 } 29 30 init(note: NdbNote) { 31 self.iter = ndb_iterator() 32 ndb_tags_iterate_start(note.note, &self.iter) 33 self.done = false 34 self.note = note 35 } 36 } 37 38 struct TagsSequence: Encodable, Sequence { 39 let note: NdbNote 40 41 var count: UInt16 { 42 note.note.pointee.tags.count 43 } 44 45 func strings() -> [[String]] { 46 return self.map { tag in 47 tag.map { t in t.string() } 48 } 49 } 50 51 func encode(to encoder: Encoder) throws { 52 var container = encoder.unkeyedContainer() 53 54 // Iterate and create the [[String]] for encoding 55 for tag in self { 56 try container.encode(tag.map { $0.string() }) 57 } 58 } 59 60 // no O(1) indexing on top-level tag lists unfortunately :( 61 // bit it's very fast to iterate over each tag since the number of tags 62 // are stored and the elements are fixed size. 63 subscript(index: Int) -> Iterator.Element { 64 var i = 0 65 for element in self { 66 if i == index { 67 return element 68 } 69 i += 1 70 } 71 precondition(false, "sequence subscript oob") 72 // it seems like the compiler needs this or it gets bitchy 73 return .init(note: .init(note: .allocate(capacity: 1), size: 0, owned: true, key: nil), tag: .allocate(capacity: 1)) 74 } 75 76 func makeIterator() -> TagsIterator { 77 return .init(note: note) 78 } 79 }