Sources/KeycaskCore/EntryID.swift
45 lines · 1521 bytes
1public struct EntryID: Hashable, Sendable, CustomStringConvertible {
2 public static let alphabet: [Character] = Array("abcdefghijkmnpqrstuvwxyz23456789")
3 public static let length = 8
4
5 public let rawValue: String
6
7 public init?(_ raw: String) {
8 guard raw.count == Self.length else { return nil }
9 let allowed = Set(Self.alphabet)
10 guard raw.allSatisfy({ allowed.contains($0) }) else { return nil }
11 rawValue = raw
12 }
13
14 public static func random() -> EntryID {
15 var rng = SystemRandomNumberGenerator()
16 return random(using: &rng)
17 }
18
19 public static func random(using rng: inout some RandomNumberGenerator) -> EntryID {
20 var chars: [Character] = []
21 chars.reserveCapacity(length)
22 for _ in 0..<length {
23 chars.append(alphabet[Int(rng.next(upperBound: UInt32(alphabet.count)))])
24 }
25 return EntryID(String(chars))!
26 }
27
28 public var description: String { rawValue }
29}
30
31extension EntryID: Codable {
32 public init(from decoder: any Decoder) throws {
33 let raw = try decoder.singleValueContainer().decode(String.self)
34 guard let id = EntryID(raw) else {
35 throw DecodingError.dataCorrupted(
36 .init(codingPath: decoder.codingPath, debugDescription: "invalid entry id \(raw)"))
37 }
38 self = id
39 }
40
41 public func encode(to encoder: any Encoder) throws {
42 var container = encoder.singleValueContainer()
43 try container.encode(rawValue)
44 }
45}