Skip to content

Commit 72fa98c

Browse files
committed
[stdlib] Result: Initial support for noncopyable payloads
1 parent 3cb9b33 commit 72fa98c

File tree

1 file changed

+110
-24
lines changed

1 file changed

+110
-24
lines changed

stdlib/public/core/Result.swift

Lines changed: 110 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2018 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2018 - 2024 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -13,13 +13,23 @@
1313
/// A value that represents either a success or a failure, including an
1414
/// associated value in each case.
1515
@frozen
16-
public enum Result<Success, Failure: Error> {
16+
public enum Result<Success: ~Copyable, Failure: Error> {
1717
/// A success, storing a `Success` value.
1818
case success(Success)
19-
19+
2020
/// A failure, storing a `Failure` value.
2121
case failure(Failure)
22-
22+
}
23+
24+
extension Result: Copyable where Success: Copyable {}
25+
26+
extension Result: Sendable where Success: Sendable & ~Copyable {}
27+
28+
extension Result: Equatable where Success: Equatable, Failure: Equatable {}
29+
30+
extension Result: Hashable where Success: Hashable, Failure: Hashable {}
31+
32+
extension Result {
2333
/// Returns a new result, mapping any success value using the given
2434
/// transformation.
2535
///
@@ -39,7 +49,8 @@ public enum Result<Success, Failure: Error> {
3949
/// - Returns: A `Result` instance with the result of evaluating `transform`
4050
/// as the new success value if this instance represents a success.
4151
@inlinable
42-
public func map<NewSuccess>(
52+
@_preInverseGenerics
53+
public func map<NewSuccess: ~Copyable>(
4354
_ transform: (Success) -> NewSuccess
4455
) -> Result<NewSuccess, Failure> {
4556
switch self {
@@ -49,7 +60,37 @@ public enum Result<Success, Failure: Error> {
4960
return .failure(failure)
5061
}
5162
}
52-
63+
}
64+
65+
extension Result where Success: ~Copyable {
66+
@_alwaysEmitIntoClient
67+
public consuming func consumingMap<NewSuccess: ~Copyable>(
68+
_ transform: (consuming Success) -> NewSuccess
69+
) -> Result<NewSuccess, Failure> {
70+
switch consume self {
71+
case let .success(success):
72+
return .success(transform(consume success))
73+
case let .failure(failure):
74+
return .failure(consume failure)
75+
}
76+
}
77+
78+
#if $BorrowingSwitch
79+
@_alwaysEmitIntoClient
80+
public borrowing func borrowingMap<NewSuccess: ~Copyable>(
81+
_ transform: (borrowing Success) -> NewSuccess
82+
) -> Result<NewSuccess, Failure> {
83+
switch self {
84+
case .success(_borrowing success):
85+
return .success(transform(success))
86+
case let .failure(failure):
87+
return .failure(failure)
88+
}
89+
}
90+
#endif
91+
}
92+
93+
extension Result where Success: ~Copyable {
5394
/// Returns a new result, mapping any failure value using the given
5495
/// transformation.
5596
///
@@ -76,8 +117,24 @@ public enum Result<Success, Failure: Error> {
76117
/// instance.
77118
/// - Returns: A `Result` instance with the result of evaluating `transform`
78119
/// as the new failure value if this instance represents a failure.
79-
@inlinable
80-
public func mapError<NewFailure>(
120+
@_alwaysEmitIntoClient
121+
public consuming func mapError<NewFailure>(
122+
_ transform: (Failure) -> NewFailure
123+
) -> Result<Success, NewFailure> {
124+
switch consume self {
125+
case let .success(success):
126+
return .success(consume success)
127+
case let .failure(failure):
128+
return .failure(transform(failure))
129+
}
130+
}
131+
}
132+
133+
extension Result {
134+
// TODO: Merge this back into the noncopyable variant once we have @_preInverseGenerics
135+
@_spi(SwiftStdlibLegacyABI) @available(swift, obsoleted: 2)
136+
@usableFromInline
137+
internal func mapError<NewFailure>(
81138
_ transform: (Failure) -> NewFailure
82139
) -> Result<Success, NewFailure> {
83140
switch self {
@@ -87,7 +144,9 @@ public enum Result<Success, Failure: Error> {
87144
return .failure(transform(failure))
88145
}
89146
}
90-
147+
}
148+
149+
extension Result {
91150
/// Returns a new result, mapping any success value using the given
92151
/// transformation and unwrapping the produced result.
93152
///
@@ -115,7 +174,8 @@ public enum Result<Success, Failure: Error> {
115174
/// - Returns: A `Result` instance, either from the closure or the previous
116175
/// `.failure`.
117176
@inlinable
118-
public func flatMap<NewSuccess>(
177+
@_preInverseGenerics
178+
public func flatMap<NewSuccess: ~Copyable>(
119179
_ transform: (Success) -> Result<NewSuccess, Failure>
120180
) -> Result<NewSuccess, Failure> {
121181
switch self {
@@ -125,13 +185,43 @@ public enum Result<Success, Failure: Error> {
125185
return .failure(failure)
126186
}
127187
}
128-
188+
}
189+
190+
extension Result where Success: ~Copyable {
191+
@_alwaysEmitIntoClient
192+
public consuming func consumingFlatMap<NewSuccess: ~Copyable>(
193+
_ transform: (consuming Success) -> Result<NewSuccess, Failure>
194+
) -> Result<NewSuccess, Failure> {
195+
switch consume self {
196+
case let .success(success):
197+
return transform(consume success)
198+
case let .failure(failure):
199+
return .failure(failure)
200+
}
201+
}
202+
203+
#if $BorrowingSwitch
204+
@_alwaysEmitIntoClient
205+
public borrowing func borrowingFlatMap<NewSuccess: ~Copyable>(
206+
_ transform: (borrowing Success) -> Result<NewSuccess, Failure>
207+
) -> Result<NewSuccess, Failure> {
208+
switch self {
209+
case .success(_borrowing success):
210+
return transform(success)
211+
case let .failure(failure):
212+
return .failure(failure)
213+
}
214+
}
215+
#endif
216+
}
217+
218+
extension Result {
129219
/// Returns a new result, mapping any failure value using the given
130220
/// transformation and unwrapping the produced result.
131221
///
132222
/// - Parameter transform: A closure that takes the failure value of the
133223
/// instance.
134-
/// - Returns: A `Result` instance, either from the closure or the previous
224+
/// - Returns: A `Result` instance, either from the closure or the previous
135225
/// `.success`.
136226
@inlinable
137227
public func flatMapError<NewFailure>(
@@ -144,7 +234,9 @@ public enum Result<Success, Failure: Error> {
144234
return transform(failure)
145235
}
146236
}
147-
237+
}
238+
239+
extension Result where Success: ~Copyable {
148240
/// Returns the success value as a throwing expression.
149241
///
150242
/// Use this method to retrieve the value of this result if it represents a
@@ -162,9 +254,8 @@ public enum Result<Success, Failure: Error> {
162254
/// - Returns: The success value, if the instance represents a success.
163255
/// - Throws: The failure value, if the instance represents a failure.
164256
@_alwaysEmitIntoClient
165-
@inlinable
166-
public func get() throws(Failure) -> Success {
167-
switch self {
257+
public consuming func get() throws(Failure) -> Success {
258+
switch consume self {
168259
case let .success(success):
169260
return success
170261
case let .failure(failure):
@@ -173,13 +264,12 @@ public enum Result<Success, Failure: Error> {
173264
}
174265
}
175266

176-
extension Result {
267+
extension Result where Success: ~Copyable {
177268
/// Creates a new result by evaluating a throwing closure, capturing the
178269
/// returned value as a success, or any thrown error as a failure.
179270
///
180271
/// - Parameter body: A potentially throwing closure to evaluate.
181272
@_alwaysEmitIntoClient
182-
@inlinable
183273
public init(catching body: () throws(Failure) -> Success) {
184274
do {
185275
self = .success(try body())
@@ -191,6 +281,7 @@ extension Result {
191281

192282
extension Result {
193283
/// ABI: Historical get() throws
284+
@_spi(SwiftStdlibLegacyABI) @available(swift, obsoleted: 2)
194285
@_silgen_name("$ss6ResultO3getxyKF")
195286
@usableFromInline
196287
func __abi_get() throws -> Success {
@@ -206,6 +297,7 @@ extension Result {
206297

207298
extension Result where Failure == Swift.Error {
208299
/// ABI: Historical init(catching:)
300+
@_spi(SwiftStdlibLegacyABI) @available(swift, obsoleted: 2)
209301
@_silgen_name("$ss6ResultOss5Error_pRs_rlE8catchingAByxsAC_pGxyKXE_tcfC")
210302
@usableFromInline
211303
init(__abi_catching body: () throws(Failure) -> Success) {
@@ -216,9 +308,3 @@ extension Result where Failure == Swift.Error {
216308
}
217309
}
218310
}
219-
220-
extension Result: Equatable where Success: Equatable, Failure: Equatable { }
221-
222-
extension Result: Hashable where Success: Hashable, Failure: Hashable { }
223-
224-
extension Result: Sendable where Success: Sendable { }

0 commit comments

Comments
 (0)