// // PreferenceValue.swift // // Copyright 2026 Brendan Szymanski // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // SPDX-License-Identifier: GPL-3.0-or-later // import Foundation /// Converts a Swift preference type to and from a SQLite scalar value. package protocol PreferenceValue: Sendable, Equatable { /// Decodes a value read back from storage, or `nil` when the stored shape does not match. /// /// - Parameter preference: The raw value read from the preference table. /// - Returns: A decoded value, or `nil` when the storage representation is incompatible. init?(preference: StoredPreference) /// The storage representation of this value. var preferenceValue: StoredPreference { get } } extension Bool: PreferenceValue { package init?(preference: StoredPreference) { guard case .integer(let value) = preference, value == 0 || value == 1 else { return nil } self = value == 1 } package var preferenceValue: StoredPreference { .integer(self ? 1 : 0) } } extension Int: PreferenceValue { package init?(preference: StoredPreference) { guard case .integer(let value) = preference, let value = Int(exactly: value) else { return nil } self = value } package var preferenceValue: StoredPreference { .integer(Int64(self)) } } extension Double: PreferenceValue { package init?(preference: StoredPreference) { switch preference { case .real(let value): self = value case .integer(let value): self = Double(value) default: return nil } } /// Non-finite values are encoded as zero because SQLite stores NaN as SQL NULL. package var preferenceValue: StoredPreference { .real(isFinite ? self : 0) } } extension String: PreferenceValue { package init?(preference: StoredPreference) { guard case .text(let value) = preference else { return nil } self = value } package var preferenceValue: StoredPreference { .text(self) } } extension URL: PreferenceValue { package init?(preference: StoredPreference) { guard case .text(let value) = preference, let url = URL(string: value) else { return nil } self = url } package var preferenceValue: StoredPreference { .text(absoluteString) } } extension UUID: PreferenceValue { package init?(preference: StoredPreference) { guard case .text(let value) = preference, let uuid = UUID(uuidString: value) else { return nil } self = uuid } package var preferenceValue: StoredPreference { .text(uuidString) } } extension Data: PreferenceValue { package init?(preference: StoredPreference) { guard case .blob(let value) = preference else { return nil } self = value } package var preferenceValue: StoredPreference { .blob(self) } } extension PreferenceValue where Self: RawRepresentable, Self.RawValue: PreferenceValue { package init?(preference: StoredPreference) { guard let raw = RawValue(preference: preference) else { return nil } self.init(rawValue: raw) } package var preferenceValue: StoredPreference { rawValue.preferenceValue } }