Viewing is open to everyone. Downloading and starring need a GitHub sign-in.
Sign in with GitHub
CKeyTypes.swift
v0.1.0-build.85
Latest
Commit ede38f5
Sign in with GitHub to download. Each download is recorded with your GitHub username.
| 1 | import CKeyCodec |
| 2 | import Foundation |
| 3 | |
| 4 | /// An error reported by the CKey core, with its diagnostic message. |
| 5 | public struct CKeyError: Error, Equatable, CustomStringConvertible { |
| 6 | /// The core's status codes (`ckey_status`), plus configuration errors |
| 7 | /// raised by the Swift layer itself. |
| 8 | public enum Code: Int, Sendable { |
| 9 | case invalidArgument = 1 |
| 10 | case unsupportedProfile = 2 |
| 11 | case insufficientBuffer = 3 |
| 12 | case internalError = 4 |
| 13 | case uncorrectable = 5 |
| 14 | case integrityFailure = 6 |
| 15 | /// An image could not be read or created (Core Graphics). |
| 16 | case imageConversion = 100 |
| 17 | /// A configuration value is out of range (for example a telemetry |
| 18 | /// mode other than 0, 1 or 2). |
| 19 | case invalidConfiguration = 101 |
| 20 | /// Camera access was denied or restricted by the user or by policy. |
| 21 | case cameraAccessDenied = 102 |
| 22 | /// No usable camera, or it could not be configured or started. |
| 23 | case cameraUnavailable = 103 |
| 24 | } |
| 25 | |
| 26 | public let code: Code |
| 27 | public let message: String |
| 28 | |
| 29 | public init(_ code: Code, _ message: String) { |
| 30 | self.code = code |
| 31 | self.message = message |
| 32 | } |
| 33 | |
| 34 | public var description: String { "CKeyError(\(code)): \(message)" } |
| 35 | |
| 36 | /// Wraps a non-OK core status. Internal plumbing shared by the CKey module. |
| 37 | public static func core(_ status: ckey_status, _ diagnostics: ckey_diagnostics? = nil, |
| 38 | _ fallback: String = "") -> CKeyError { |
| 39 | let code = Code(rawValue: Int(status.rawValue)) ?? .internalError |
| 40 | var text = fallback |
| 41 | if let diagnostics { |
| 42 | let message = CKeyError.string(fromDiagnostics: diagnostics) |
| 43 | if !message.isEmpty { text = message } |
| 44 | } |
| 45 | if text.isEmpty { text = "CKey core status \(status.rawValue)" } |
| 46 | return CKeyError(code, text) |
| 47 | } |
| 48 | |
| 49 | static func string(fromDiagnostics diagnostics: ckey_diagnostics) -> String { |
| 50 | withUnsafeBytes(of: diagnostics.message) { raw -> String in |
| 51 | let bytes = raw.bindMemory(to: UInt8.self) |
| 52 | let end = bytes.firstIndex(of: 0) ?? bytes.count |
| 53 | return String(decoding: bytes[0..<end], as: UTF8.self) |
| 54 | } |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | /// Profile 0 layout family. |
| 59 | public enum CKeyLayout: Int, Sendable, CaseIterable { |
| 60 | /// Format 0.27: the default screen and print layout. |
| 61 | case standard = 0 |
| 62 | /// Format 0.28 ("P0.1"): larger marks and gaps for small prints, at a |
| 63 | /// lower capacity per version. |
| 64 | case print = 1 |
| 65 | } |
| 66 | |
| 67 | /// The optical profile a symbol was read as. |
| 68 | public enum CKeyProfile: Int, Sendable, CaseIterable { |
| 69 | /// Profile 0, the scalable family (versions 1 to 31). See `CKeyResult.layout`. |
| 70 | case scalable = 0 |
| 71 | /// Profile 1: a 16-byte locator. |
| 72 | case locator = 1 |
| 73 | /// Profile 2: text, up to 200 bytes. |
| 74 | case text = 2 |
| 75 | /// Profile 3: extended, up to 2,048 bytes. |
| 76 | case extended = 3 |
| 77 | } |
| 78 | |
| 79 | /// A decoded symbol. |
| 80 | public struct CKeyResult: Equatable, Sendable { |
| 81 | /// The payload bytes, verified by Reed-Solomon correction and CRC-32C. |
| 82 | public let bytes: Data |
| 83 | /// The payload as text when it is valid UTF-8 without control characters |
| 84 | /// other than tab, LF and CR (spec/CKey-Payload-Conventions.md); `nil` |
| 85 | /// for binary payloads. |
| 86 | public let text: String? |
| 87 | public let profile: CKeyProfile |
| 88 | /// Profile 0 version (1...31); 0 for Profiles 1 to 3. |
| 89 | public let version: Int |
| 90 | /// Profile 0 layout; `nil` for Profiles 1 to 3. |
| 91 | public let layout: CKeyLayout? |
| 92 | |
| 93 | public init(bytes: Data, profile: CKeyProfile, version: Int = 0, layout: CKeyLayout? = nil) { |
| 94 | self.bytes = bytes |
| 95 | self.text = CKeyPayload.text(from: bytes) |
| 96 | self.profile = profile |
| 97 | self.version = version |
| 98 | self.layout = layout |
| 99 | } |
| 100 | |
| 101 | /// The telemetry profile code (`ckey_telemetry_profile`): 0 = P0, |
| 102 | /// 1 = P0.1 (print layout), 2 = P1, 3 = P2, 4 = P3. |
| 103 | public var telemetryProfileCode: UInt32 { |
| 104 | switch profile { |
| 105 | case .scalable: return layout == .print ? 1 : 0 |
| 106 | case .locator: return 2 |
| 107 | case .text: return 3 |
| 108 | case .extended: return 4 |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | /// A short human-readable profile name, e.g. "Profile 0 · v3". |
| 113 | public var profileDescription: String { |
| 114 | switch profile { |
| 115 | case .scalable: return layout == .print ? "Profile 0.1 · print · v\(version)" : "Profile 0 · v\(version)" |
| 116 | case .locator: return "Profile 1 · Locator" |
| 117 | case .text: return "Profile 2 · Text" |
| 118 | case .extended: return "Profile 3 · Extended" |
| 119 | } |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | /// Versions of the linked core. |
| 124 | public enum CKeyCoreInfo { |
| 125 | /// The core's software version, e.g. "0.1.0-build.63" (the repository's VERSION). |
| 126 | public static var softwareVersion: String { |
| 127 | ckey_get_software_version().map { String(cString: $0) } ?? "0.0.0" |
| 128 | } |
| 129 | |
| 130 | /// The C ABI version of the linked core. |
| 131 | public static var abiVersion: UInt32 { ckey_get_abi_version() } |
| 132 | } |