-
Notifications
You must be signed in to change notification settings - Fork 44
Expand file tree
/
Copy pathNonEmpty.swift
More file actions
174 lines (139 loc) · 4.93 KB
/
NonEmpty.swift
File metadata and controls
174 lines (139 loc) · 4.93 KB
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
174
@dynamicMemberLookup
public struct NonEmpty<Collection: Swift.Collection>: Swift.Collection {
public typealias Element = Collection.Element
public typealias Index = Collection.Index
public internal(set) var rawValue: Collection
public init?(rawValue: Collection) {
guard !rawValue.isEmpty else { return nil }
self.rawValue = rawValue
}
public subscript<Subject>(dynamicMember keyPath: KeyPath<Collection, Subject>) -> Subject {
self.rawValue[keyPath: keyPath]
}
public var startIndex: Index { self.rawValue.startIndex }
public var endIndex: Index { self.rawValue.endIndex }
public subscript(position: Index) -> Element { self.rawValue[position] }
@inlinable
public func index(after i: Index) -> Index {
self.rawValue.index(after: i)
}
public var first: Element { self.rawValue.first! }
@inlinable
public func max(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> Element {
try self.rawValue.max(by: areInIncreasingOrder)!
}
@inlinable
public func min(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> Element {
try self.rawValue.min(by: areInIncreasingOrder)!
}
@inlinable
public func sorted(
by areInIncreasingOrder: (Element, Element) throws -> Bool
) rethrows -> NonEmpty<[Element]> {
NonEmpty<[Element]>(rawValue: try self.rawValue.sorted(by: areInIncreasingOrder))!
}
@inlinable
public func randomElement<T>(using generator: inout T) -> Element where T: RandomNumberGenerator {
self.rawValue.randomElement(using: &generator)!
}
@inlinable
public func randomElement() -> Element {
self.rawValue.randomElement()!
}
@inlinable
public func shuffled<T>(using generator: inout T) -> NonEmpty<[Element]>
where T: RandomNumberGenerator {
NonEmpty<[Element]>(rawValue: self.rawValue.shuffled(using: &generator))!
}
@inlinable
public func shuffled() -> NonEmpty<[Element]> {
NonEmpty<[Element]>(rawValue: self.rawValue.shuffled())!
}
@inlinable
public func map<T>(_ transform: (Element) throws -> T) rethrows -> NonEmpty<[T]> {
NonEmpty<[T]>(rawValue: try self.rawValue.map(transform))!
}
@inlinable
public func flatMap<SegmentOfResult>(
_ transform: (Element) throws -> NonEmpty<SegmentOfResult>
) rethrows -> NonEmpty<[SegmentOfResult.Element]> where SegmentOfResult: Sequence {
NonEmpty<[SegmentOfResult.Element]>(rawValue: try self.rawValue.flatMap(transform))!
}
}
extension NonEmpty: CustomStringConvertible {
public var description: String {
return String(describing: self.rawValue)
}
}
extension NonEmpty: Equatable where Collection: Equatable {}
extension NonEmpty: Hashable where Collection: Hashable {}
extension NonEmpty: Comparable where Collection: Comparable {
public static func < (lhs: Self, rhs: Self) -> Bool {
lhs.rawValue < rhs.rawValue
}
}
#if canImport(_Concurrency) && compiler(>=5.5)
extension NonEmpty: Sendable where Collection: Sendable {}
#endif
extension NonEmpty: Encodable where Collection: Encodable {
@inlinable
public func encode(to encoder: Encoder) throws {
do {
var container = encoder.singleValueContainer()
try container.encode(self.rawValue)
} catch {
try self.rawValue.encode(to: encoder)
}
}
}
extension NonEmpty: Decodable where Collection: Decodable {
public init(from decoder: Decoder) throws {
let collection: Collection
do {
collection = try decoder.singleValueContainer().decode(Collection.self)
} catch {
collection = try Collection(from: decoder)
}
guard !collection.isEmpty else {
throw DecodingError.dataCorrupted(
.init(codingPath: decoder.codingPath, debugDescription: "Non-empty collection expected")
)
}
self.init(rawValue: collection)!
}
}
extension NonEmpty: RawRepresentable {}
extension NonEmpty where Collection.Element: Comparable {
@inlinable
public func max() -> Element {
self.rawValue.max()!
}
@inlinable
public func min() -> Element {
self.rawValue.min()!
}
@inlinable
public func sorted() -> NonEmpty<[Element]> {
return NonEmpty<[Element]>(rawValue: self.rawValue.sorted())!
}
}
extension NonEmpty: BidirectionalCollection where Collection: BidirectionalCollection {
@inlinable
public func index(before i: Index) -> Index {
self.rawValue.index(before: i)
}
public var last: Element { self.rawValue.last! }
}
extension NonEmpty: MutableCollection where Collection: MutableCollection {
public subscript(position: Index) -> Element {
_read { yield self.rawValue[position] }
_modify { yield &self.rawValue[position] }
}
}
extension NonEmpty: RandomAccessCollection where Collection: RandomAccessCollection {}
extension NonEmpty where Collection: MutableCollection & RandomAccessCollection {
public mutating func shuffle<T: RandomNumberGenerator>(using generator: inout T) {
self.rawValue.shuffle(using: &generator)
}
}
public typealias NonEmptyArray<Element> = NonEmpty<[Element]>