13
13
import CoreFoundation
14
14
import Darwin
15
15
16
+ /// Describes an error that provides localized messages describing why
17
+ /// an error occurred and provides more information about the error.
18
+ public protocol LocalizedError : ErrorProtocol {
19
+ /// A localized message describing what error occurred.
20
+ var errorDescription : String ? { get }
21
+
22
+ /// A localized message describing the reason for the failure.
23
+ var failureReason : String ? { get }
24
+
25
+ /// A localized message describing how one might recover from the failure.
26
+ var recoverySuggestion : String ? { get }
27
+
28
+ /// A localized message providing "help" text if the user requests help.
29
+ var helpAnchor : String ? { get }
30
+ }
31
+
32
+ public extension LocalizedError {
33
+ var errorDescription : String ? { return nil }
34
+ var failureReason : String ? { return nil }
35
+ var recoverySuggestion : String ? { return nil }
36
+ var helpAnchor : String ? { return nil }
37
+ }
38
+
39
+ @_silgen_name ( " NS_Swift_performErrorRecoverySelector " )
40
+ internal func NS_Swift_performErrorRecoverySelector(
41
+ delegate: AnyObject ? ,
42
+ selector: Selector ,
43
+ success: ObjCBool ,
44
+ contextInfo: UnsafeMutablePointer < Void > ? )
45
+
46
+ /// Class that implements the informal protocol
47
+ /// NSErrorRecoveryAttempting, which is used by NSError when it
48
+ /// attempts recovery from an error.
49
+ class _NSErrorRecoveryAttempter {
50
+ // FIXME: If we could meaningfully cast the nsError back to RecoverableError,
51
+ // we wouldn't need to capture this and could use the user-info
52
+ // domain providers even for recoverable errors.
53
+ let error : RecoverableError
54
+
55
+ init ( error: RecoverableError) {
56
+ self . error = error
57
+ }
58
+
59
+ @objc ( attemptRecoveryFromError: optionIndex: delegate: didRecoverSelector: contextInfo: )
60
+ func attemptRecovery( fromError nsError: NSError ,
61
+ optionIndex recoveryOptionIndex: Int ,
62
+ delegate: AnyObject ? ,
63
+ didRecoverSelector: Selector ,
64
+ contextInfo: UnsafeMutablePointer < Void > ? ) {
65
+ error. attemptRecovery ( optionIndex: recoveryOptionIndex) { success in
66
+ NS_Swift_performErrorRecoverySelector (
67
+ delegate: delegate,
68
+ selector: didRecoverSelector,
69
+ success: ObjCBool ( success) ,
70
+ contextInfo: contextInfo)
71
+ }
72
+ }
73
+
74
+ @objc ( attemptRecoveryFromError: optionIndex: )
75
+ func attemptRecovery( fromError nsError: NSError ,
76
+ optionIndex recoveryOptionIndex: Int ) -> Bool {
77
+ return error. attemptRecovery ( optionIndex: recoveryOptionIndex)
78
+ }
79
+ }
80
+
81
+ /// Describes an error that may be recoverably by presenting several
82
+ /// potential recovery options to the user.
83
+ public protocol RecoverableError : ErrorProtocol {
84
+ /// Provides a set of possible recovery options to present to the user.
85
+ var recoveryOptions : [ String ] { get }
86
+
87
+ /// Attempt to recover from this error when the user selected the
88
+ /// option at the given index. This routine must call resultHandler and
89
+ /// indicate whether recovery was successful (or not).
90
+ ///
91
+ /// This entry point is used for recovery of errors handled at a
92
+ /// "document" granularity, that do not affect the entire
93
+ /// application.
94
+ func attemptRecovery( optionIndex recoveryOptionIndex: Int ,
95
+ andThen resultHandler: ( recovered: Bool ) -> Void )
96
+
97
+ /// Attempt to recover from this error when the user selected the
98
+ /// option at the given index. Returns true to indicate
99
+ /// successful recovery, and false otherwise.
100
+ ///
101
+ /// This entry point is used for recovery of errors handled at
102
+ /// the "application" granularity, where nothing else in the
103
+ /// application can proceed until the attmpted error recovery
104
+ /// completes.
105
+ func attemptRecovery( optionIndex recoveryOptionIndex: Int ) -> Bool
106
+ }
107
+
108
+ public extension RecoverableError {
109
+ /// By default, implements document-modal recovery via application-model
110
+ /// recovery.
111
+ func attemptRecovery( optionIndex recoveryOptionIndex: Int ,
112
+ andThen resultHandler: ( recovered: Bool ) -> Void ) {
113
+ resultHandler ( recovered: attemptRecovery ( optionIndex: recoveryOptionIndex) )
114
+ }
115
+ }
116
+
117
+ /// Describes an error type that specifically provides a domain, code,
118
+ /// and user-info dictionary.
119
+ public protocol CustomNSError : ErrorProtocol {
120
+ /// The domain of the error.
121
+ var errorDomain : String { get }
122
+
123
+ /// The error code within the given domain.
124
+ var errorCode : Int { get }
125
+
126
+ /// The user-info dictionary.
127
+ var errorUserInfo : [ String : AnyObject ] { get }
128
+ }
129
+
130
+ public extension ErrorProtocol where Self : CustomNSError {
131
+ /// Default implementation for customized NSErrors.
132
+ var _domain : String { return self . errorDomain }
133
+
134
+ /// Default implementation for customized NSErrors.
135
+ var _code : Int { return self . errorCode }
136
+ }
137
+
138
+ /// Retrieve the default userInfo dictionary for a given error.
139
+ @_silgen_name ( " swift_Foundation_getErrorDefaultUserInfo " )
140
+ public func _swift_Foundation_getErrorDefaultUserInfo( _ error: ErrorProtocol )
141
+ -> AnyObject ? {
142
+ // If the OS supports value user info value providers, use those
143
+ // to lazily populate the user-info dictionary for this domain.
144
+ if #available( OSX 10 . 11 , iOS 9 . 0 , tvOS 9 . 0 , watchOS 2 . 0 , * ) {
145
+ // FIXME: This is not implementable until we can recover the
146
+ // original error from an NSError.
147
+ }
148
+
149
+ // Populate the user-info dictionary
150
+ var result : [ String : AnyObject ]
151
+
152
+ // Initialize with custom user-info.
153
+ if let customNSError = error as? CustomNSError {
154
+ result = customNSError. errorUserInfo
155
+ } else {
156
+ result = [ : ]
157
+ }
158
+
159
+ if let localizedError = error as? LocalizedError {
160
+ if let description = localizedError. errorDescription {
161
+ result [ NSLocalizedDescriptionKey] = description as AnyObject
162
+ }
163
+
164
+ if let reason = localizedError. failureReason {
165
+ result [ NSLocalizedFailureReasonErrorKey] = reason as AnyObject
166
+ }
167
+
168
+ if let suggestion = localizedError. recoverySuggestion {
169
+ result [ NSLocalizedRecoverySuggestionErrorKey] = suggestion as AnyObject
170
+ }
171
+
172
+ if let helpAnchor = localizedError. helpAnchor {
173
+ result [ NSHelpAnchorErrorKey] = helpAnchor as AnyObject
174
+ }
175
+ }
176
+
177
+ if let recoverableError = error as? RecoverableError {
178
+ result [ NSLocalizedRecoveryOptionsErrorKey] =
179
+ recoverableError. recoveryOptions as AnyObject
180
+ result [ NSRecoveryAttempterErrorKey] =
181
+ _NSErrorRecoveryAttempter ( error: recoverableError)
182
+ }
183
+
184
+ return result as AnyObject
185
+ }
186
+
16
187
// NSError and CFError conform to the standard ErrorProtocol protocol. Compiler
17
188
// magic allows this to be done as a "toll-free" conversion when an NSError
18
189
// or CFError is used as an ErrorProtocol existential.
19
190
20
191
extension NSError : ErrorProtocol {
21
192
public var _domain : String { return domain }
22
193
public var _code : Int { return code }
194
+ public var _userInfo : AnyObject ? { return userInfo as AnyObject }
23
195
}
24
196
25
197
extension CFError : ErrorProtocol {
@@ -30,6 +202,10 @@ extension CFError : ErrorProtocol {
30
202
public var _code : Int {
31
203
return CFErrorGetCode ( self )
32
204
}
205
+
206
+ public var _userInfo : AnyObject ? {
207
+ return CFErrorCopyUserInfo ( self ) as AnyObject ?
208
+ }
33
209
}
34
210
35
211
// An error value to use when an Objective-C API indicates error
0 commit comments