-
-
Notifications
You must be signed in to change notification settings - Fork 114
/
Defaults+Protocol.swift
173 lines (137 loc) · 4.16 KB
/
Defaults+Protocol.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
import Foundation
extension Defaults {
/**
Types that conform to this protocol can be used with `Defaults`.
The type should have a static variable `bridge` which should reference an instance of a type that conforms to `Defaults.Bridge`.
```swift
struct User {
username: String
password: String
}
extension User: Defaults.Serializable {
static let bridge = UserBridge()
}
```
*/
public protocol Serializable {
typealias Value = Bridge.Value
typealias Serializable = Bridge.Serializable
associatedtype Bridge: Defaults.Bridge
/**
Static bridge for the `Value` which cannot be stored natively.
*/
static var bridge: Bridge { get }
/**
A flag to determine whether `Value` can be stored natively or not.
*/
static var isNativelySupportedType: Bool { get }
}
}
extension Defaults {
public protocol Bridge {
associatedtype Value
associatedtype Serializable
func serialize(_ value: Value?) -> Serializable?
func deserialize(_ object: Serializable?) -> Value?
}
}
extension Defaults {
/**
Ambiguous bridge selector protocol that lets you select your preferred bridge when there are multiple possibilities.
```swift
enum Interval: Int, Codable, Defaults.Serializable, Defaults.PreferRawRepresentable {
case tenMinutes = 10
case halfHour = 30
case oneHour = 60
}
```
By default, if an `enum` conforms to `Codable` and `Defaults.Serializable`, it will use the `CodableBridge`, but by conforming to `Defaults.PreferRawRepresentable`, we can switch the bridge back to `RawRepresentableBridge`.
*/
public protocol PreferRawRepresentable: RawRepresentable {}
/**
Ambiguous bridge selector protocol that lets you select your preferred bridge when there are multiple possibilities.
*/
public protocol PreferNSSecureCoding: NSObject, NSSecureCoding {}
}
extension Defaults {
public protocol CollectionSerializable: Collection, Serializable {
/**
`Collection` does not have a initializer, but we need a initializer to convert an array into the `Value`.
*/
init(_ elements: [Element])
}
public protocol SetAlgebraSerializable: SetAlgebra, Serializable {
/**
Since `SetAlgebra` protocol does not conform to `Sequence`, we cannot convert a `SetAlgebra` to an `Array` directly.
*/
func toArray() -> [Element]
}
public protocol CodableBridge: Bridge where Serializable == String, Value: Codable {}
// Essential properties for serializing and deserializing `ClosedRange` and `Range`.
public protocol Range {
associatedtype Bound: Comparable, Defaults.Serializable
var lowerBound: Bound { get }
var upperBound: Bound { get }
init(uncheckedBounds: (lower: Bound, upper: Bound))
}
/**
A `Bridge` is responsible for serialization and deserialization.
It has two associated types `Value` and `Serializable`.
- `Value`: The type you want to use.
- `Serializable`: The type stored in `UserDefaults`.
- `serialize`: Executed before storing to the `UserDefaults` .
- `deserialize`: Executed after retrieving its value from the `UserDefaults`.
```swift
struct User {
username: String
password: String
}
extension User {
static let bridge = UserBridge()
}
struct UserBridge: Defaults.Bridge {
typealias Value = User
typealias Serializable = [String: String]
func serialize(_ value: Value?) -> Serializable? {
guard let value else {
return nil
}
return [
"username": value.username,
"password": value.password
]
}
func deserialize(_ object: Serializable?) -> Value? {
guard
let object,
let username = object["username"],
let password = object["password"]
else {
return nil
}
return User(
username: username,
password: password
)
}
}
```
*/
public typealias RangeSerializable = Defaults.Range & Serializable
}
/**
Essential properties for synchronizing a key value store.
*/
protocol DefaultsKeyValueStore {
func object(forKey aKey: String) -> Any?
func set(_ anObject: Any?, forKey aKey: String)
func removeObject(forKey aKey: String)
@discardableResult
func synchronize() -> Bool
}
protocol DefaultsLockProtocol {
static func make() -> Self
func lock()
func unlock()
func with<R>(_ body: @Sendable () throws -> R) rethrows -> R where R: Sendable
}