damus

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

ReferencedId.swift (4574B)


      1 //
      2 //  ReferencedId.swift
      3 //  damus
      4 //
      5 //  Created by William Casarin on 2023-07-22.
      6 //
      7 
      8 import Foundation
      9 
     10 func tagref_should_be_id(_ tag: NdbTagElem) -> Bool {
     11     return !(tag.matches_char("t") || tag.matches_char("d"))
     12 }
     13 
     14 
     15 struct References<T: TagConvertible>: Sequence, IteratorProtocol {
     16     let tags: TagsSequence
     17     var tags_iter: TagsIterator
     18 
     19     init(tags: TagsSequence) {
     20         self.tags = tags
     21         self.tags_iter = tags.makeIterator()
     22     }
     23 
     24     mutating func next() -> T? {
     25         while let tag = tags_iter.next() {
     26             guard let evref = T.from_tag(tag: tag) else { continue }
     27             return evref
     28         }
     29         return nil
     30     }
     31 }
     32 
     33 extension References {
     34     var first: T? {
     35         self.first(where: { _ in true })
     36     }
     37 
     38     var last: T? {
     39         var last: T? = nil
     40         for t in self {
     41             last = t
     42         }
     43         return last
     44     }
     45 }
     46 
     47 
     48 // NdbTagElem transition helpers
     49 extension String {
     50     func string() -> String {
     51         return self
     52     }
     53 
     54     func first_char() -> AsciiCharacter? {
     55         self.first.flatMap { chr in AsciiCharacter(chr) }
     56     }
     57 
     58     func matches_char(_ c: AsciiCharacter) -> Bool {
     59         return self.first == c.character
     60     }
     61     
     62     func matches_str(_ str: String) -> Bool {
     63         return self == str
     64     }
     65 }
     66 
     67 enum FollowRef: TagKeys, Hashable, TagConvertible, Equatable {
     68 
     69     // NOTE: When adding cases make sure to update key and from_tag
     70     case pubkey(Pubkey)
     71     case hashtag(String)
     72 
     73     var key: FollowKeys {
     74         switch self {
     75         case .hashtag: return .t
     76         case .pubkey:  return .p
     77         }
     78     }
     79 
     80     enum FollowKeys: AsciiCharacter, TagKey, CustomStringConvertible {
     81         case p, t
     82 
     83         var keychar: AsciiCharacter { self.rawValue }
     84         var description: String { self.rawValue.description }
     85     }
     86 
     87     static func from_tag(tag: TagSequence) -> FollowRef? {
     88         guard tag.count >= 2 else { return nil }
     89 
     90         var i = tag.makeIterator()
     91 
     92         guard let t0   = i.next(),
     93               let c    = t0.single_char,
     94               let fkey = FollowKeys(rawValue: c),
     95               let t1   = i.next()
     96         else {
     97             return nil
     98         }
     99 
    100         switch fkey {
    101         case .p: return t1.id().map({ .pubkey(Pubkey($0)) })
    102         case .t: return .hashtag(t1.string())
    103         }
    104     }
    105 
    106     var tag: [String] {
    107         [key.description, self.description]
    108     }
    109 
    110     var description: String {
    111         switch self {
    112         case .pubkey(let pubkey): return pubkey.description
    113         case .hashtag(let string): return string
    114         }
    115     }
    116 }
    117 
    118 enum RefId: TagConvertible, TagKeys, Equatable, Hashable {
    119     case event(NoteId)
    120     case pubkey(Pubkey)
    121     case quote(QuoteId)
    122     case hashtag(Hashtag)
    123     case param(TagElem)
    124     case naddr(NAddr)
    125     
    126     var key: RefKey {
    127         switch self {
    128         case .event:   return .e
    129         case .pubkey:  return .p
    130         case .quote:   return .q
    131         case .hashtag: return .t
    132         case .param:   return .d
    133         case .naddr:   return .a
    134         }
    135     }
    136 
    137     enum RefKey: AsciiCharacter, TagKey, CustomStringConvertible {
    138         case e, p, t, d, q, a
    139 
    140         var keychar: AsciiCharacter {
    141             self.rawValue
    142         }
    143 
    144         var description: String {
    145             self.keychar.description
    146         }
    147     }
    148 
    149     var tag: [String] {
    150         [self.key.description, self.description]
    151     }
    152 
    153     var description: String {
    154         switch self {
    155         case .event(let noteId): return noteId.hex()
    156         case .pubkey(let pubkey): return pubkey.hex()
    157         case .quote(let quote): return quote.hex()
    158         case .hashtag(let string): return string.hashtag
    159         case .param(let string): return string.string()
    160         case .naddr(let naddr):
    161             return naddr.kind.description + ":" + naddr.author.hex() + ":" + naddr.identifier
    162         }
    163     }
    164 
    165     static func from_tag(tag: TagSequence) -> RefId? {
    166         var i = tag.makeIterator()
    167 
    168         guard tag.count >= 2,
    169               let t0 = i.next(),
    170               let key = t0.single_char,
    171               let rkey = RefKey(rawValue: key),
    172               let t1 = i.next()
    173         else { return nil }
    174 
    175         switch rkey {
    176         case .e: return t1.id().map({ .event(NoteId($0)) })
    177         case .p: return t1.id().map({ .pubkey(Pubkey($0)) })
    178         case .q: return t1.id().map({ .quote(QuoteId($0)) })
    179         case .t: return .hashtag(Hashtag(hashtag: t1.string()))
    180         case .d: return .param(t1)
    181         case .a: return .naddr(NAddr(identifier: "", author: Pubkey(Data()), relays: [], kind: 0))
    182         }
    183     }
    184 }
    185