mirror of https://github.com/oxen-io/session-ios
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
114 lines
3.2 KiB
Swift
114 lines
3.2 KiB
Swift
3 years ago
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||
|
|
||
|
import Foundation
|
||
|
|
||
|
public enum Updatable<Wrapped>: ExpressibleByNilLiteral {
|
||
|
/// A cleared value.
|
||
|
///
|
||
|
/// In code, the cleared of a value is typically written using the `nil`
|
||
|
/// literal rather than the explicit `.remove` enumeration case.
|
||
|
case remove
|
||
|
|
||
|
/// The existing value, this will leave whatever value is currently available.
|
||
|
case existing
|
||
|
|
||
|
/// An updated value, stored as `Wrapped`.
|
||
|
case update(Wrapped)
|
||
|
|
||
|
// MARK: - ExpressibleByNilLiteral
|
||
|
|
||
|
public init(nilLiteral: ()) {
|
||
|
self = .remove
|
||
|
}
|
||
|
|
||
|
public static func updateIf(_ maybeValue: Wrapped?) -> Updatable<Wrapped> {
|
||
|
switch maybeValue {
|
||
|
case .some(let value): return .update(value)
|
||
|
default: return .existing
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static func updateTo(_ maybeValue: Wrapped?) -> Updatable<Wrapped> {
|
||
|
switch maybeValue {
|
||
|
case .some(let value): return .update(value)
|
||
|
default: return .remove
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// MARK: - Functions
|
||
|
|
||
|
public func value(existing: Wrapped) -> Wrapped? {
|
||
|
switch self {
|
||
|
case .remove: return nil
|
||
|
case .existing: return existing
|
||
|
case .update(let newValue): return newValue
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public func value(existing: Wrapped) -> Wrapped {
|
||
|
switch self {
|
||
|
case .remove: fatalError("Attempted to assign a 'removed' value to a non-null")
|
||
|
case .existing: return existing
|
||
|
case .update(let newValue): return newValue
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// MARK: - Coalesing-nil operator
|
||
|
|
||
|
public func ?? <T>(updatable: Updatable<T>, existingValue: @autoclosure () throws -> T) rethrows -> T {
|
||
|
switch updatable {
|
||
|
case .remove: fatalError("Attempted to assign a 'removed' value to a non-null")
|
||
|
case .existing: return try existingValue()
|
||
|
case .update(let newValue): return newValue
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public func ?? <T>(updatable: Updatable<T>, existingValue: @autoclosure () throws -> T?) rethrows -> T? {
|
||
|
switch updatable {
|
||
|
case .remove: return nil
|
||
|
case .existing: return try existingValue()
|
||
|
case .update(let newValue): return newValue
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// MARK: - ExpressibleBy Conformance
|
||
|
|
||
|
extension Updatable {
|
||
|
public init(_ value: Wrapped) {
|
||
|
self = .update(value)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
extension Updatable: ExpressibleByUnicodeScalarLiteral, ExpressibleByExtendedGraphemeClusterLiteral, ExpressibleByStringLiteral where Wrapped == String {
|
||
|
public init(stringLiteral value: Wrapped) {
|
||
|
self = .update(value)
|
||
|
}
|
||
|
|
||
|
public init(extendedGraphemeClusterLiteral value: Wrapped) {
|
||
|
self = .update(value)
|
||
|
}
|
||
|
|
||
|
public init(unicodeScalarLiteral value: Wrapped) {
|
||
|
self = .update(value)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
extension Updatable: ExpressibleByIntegerLiteral where Wrapped == Int {
|
||
|
public init(integerLiteral value: Int) {
|
||
|
self = .update(value)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
extension Updatable: ExpressibleByFloatLiteral where Wrapped == Double {
|
||
|
public init(floatLiteral value: Double) {
|
||
|
self = .update(value)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
extension Updatable: ExpressibleByBooleanLiteral where Wrapped == Bool {
|
||
|
public init(booleanLiteral value: Bool) {
|
||
|
self = .update(value)
|
||
|
}
|
||
|
}
|