-
Notifications
You must be signed in to change notification settings - Fork 3.6k
[pigeon][swift] Removes FlutterError in favor of PigeonError #6611
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
c510bd6
d8968d7
c2beea1
6a8a94c
b874f09
df102e3
b30a0cc
30ac050
92c97af
86d9168
20ac87a
800ba60
8fa6b75
4bd3dbc
fae49ea
b386a96
78c3bb6
f13a06a
63df915
428736d
88cd27d
a78cae7
4ed7852
a8ab4f8
877015d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
Swift has more strict type system than Objective-C. For example, protocol conformance must not be redundant[1]. Also, Both FlutterError and Swift.Error are public, extension `FlutterError` to `Swift.Error` is also public. If someone create a such extension in the plugin code, Flutter app can't create a such extension in the app code, which forces Plugin developers to use Objective-C when they want to use pigeon, instead of Swift. To avoid this issue, this change makes pigeon to use another error type, named PigeonError, instead of FlutterError. By declaring PigeonError as internal visibility, their existence won't make compilation error even if PigeonError is declared in the app code. [1] https://docs.swift.org/swift-book/documentation/the-swift-programming-language/declarations/#Protocol-Conformance-Must-Not-Be-Redundant
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,6 +14,32 @@ import Foundation | |
| #error("Unsupported platform.") | ||
| #endif | ||
|
|
||
| /// Error thrown by Pigeon. Encapsulates a code, message, and details. | ||
| class PigeonError: Swift.Error { | ||
| let code: String | ||
| let message: String? | ||
| let details: Any? | ||
|
|
||
| init(code: String, message: String?, details: Any?) { | ||
| self.code = code | ||
| self.message = message | ||
| self.details = details | ||
| } | ||
|
|
||
| var localizedDescription: String { | ||
| let detailsDescription: String | ||
| if let convertibleObject = details as? CustomStringConvertible { | ||
|
||
| detailsDescription = convertibleObject.description | ||
| } else if let _ = details { | ||
| detailsDescription = "<non-convertible object>" | ||
| } else { | ||
| detailsDescription = "<nil>" | ||
| } | ||
| return | ||
| "PigeonError(code: \(code), message: \(message ?? "<nil>"), details: \(detailsDescription)" | ||
| } | ||
| } | ||
|
|
||
| private func wrapResult(_ result: Any?) -> [Any?] { | ||
| return [result] | ||
| } | ||
|
|
@@ -33,8 +59,8 @@ private func wrapError(_ error: Any) -> [Any?] { | |
| ] | ||
| } | ||
|
|
||
| private func createConnectionError(withChannelName channelName: String) -> FlutterError { | ||
| return FlutterError( | ||
| private func createConnectionError(withChannelName channelName: String) -> PigeonError { | ||
| return PigeonError( | ||
| code: "channel-error", message: "Unable to establish connection on channel: '\(channelName)'.", | ||
| details: "") | ||
| } | ||
|
|
@@ -193,7 +219,7 @@ class ExampleHostApiSetup { | |
| /// Generated protocol from Pigeon that represents Flutter messages that can be called from Swift. | ||
| protocol MessageFlutterApiProtocol { | ||
| func flutterMethod( | ||
| aString aStringArg: String?, completion: @escaping (Result<String, FlutterError>) -> Void) | ||
| aString aStringArg: String?, completion: @escaping (Result<String, PigeonError>) -> Void) | ||
| } | ||
| class MessageFlutterApi: MessageFlutterApiProtocol { | ||
| private let binaryMessenger: FlutterBinaryMessenger | ||
|
|
@@ -203,7 +229,7 @@ class MessageFlutterApi: MessageFlutterApiProtocol { | |
| self.messageChannelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" | ||
| } | ||
| func flutterMethod( | ||
| aString aStringArg: String?, completion: @escaping (Result<String, FlutterError>) -> Void | ||
| aString aStringArg: String?, completion: @escaping (Result<String, PigeonError>) -> Void | ||
| ) { | ||
| let channelName: String = | ||
| "dev.flutter.pigeon.pigeon_example_package.MessageFlutterApi.flutterMethod\(messageChannelSuffix)" | ||
|
|
@@ -217,11 +243,11 @@ class MessageFlutterApi: MessageFlutterApiProtocol { | |
| let code: String = listResponse[0] as! String | ||
| let message: String? = nilOrValue(listResponse[1]) | ||
| let details: String? = nilOrValue(listResponse[2]) | ||
| completion(.failure(FlutterError(code: code, message: message, details: details))) | ||
| completion(.failure(PigeonError(code: code, message: message, details: details))) | ||
| } else if listResponse[0] == nil { | ||
| completion( | ||
| .failure( | ||
| FlutterError( | ||
| PigeonError( | ||
| code: "null-error", | ||
| message: "Flutter api returned null value for non-null return value.", details: ""))) | ||
| } else { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -316,7 +316,7 @@ class SwiftGenerator extends StructuredGenerator<SwiftOptions> { | |
| name: func.name, | ||
| parameters: func.parameters, | ||
| returnType: func.returnType, | ||
| errorTypeName: 'FlutterError', | ||
| errorTypeName: 'PigeonError', | ||
| isAsynchronous: true, | ||
| swiftFunction: func.swiftFunction, | ||
| getParameterName: _getSafeArgumentName, | ||
|
|
@@ -673,10 +673,10 @@ private func nilOrValue<T>(_ value: Any?) -> T? { | |
| void _writeCreateConnectionError(Indent indent) { | ||
| indent.newln(); | ||
| indent.writeScoped( | ||
| 'private func createConnectionError(withChannelName channelName: String) -> FlutterError {', | ||
| 'private func createConnectionError(withChannelName channelName: String) -> PigeonError {', | ||
|
||
| '}', () { | ||
| indent.writeln( | ||
| 'return FlutterError(code: "channel-error", message: "Unable to establish connection on channel: \'\\(channelName)\'.", details: "")'); | ||
| 'return PigeonError(code: "channel-error", message: "Unable to establish connection on channel: \'\\(channelName)\'.", details: "")'); | ||
| }); | ||
| } | ||
|
|
||
|
|
@@ -694,6 +694,8 @@ private func nilOrValue<T>(_ value: Any?) -> T? { | |
| .whereType<AstFlutterApi>() | ||
| .any((Api api) => api.methods.isNotEmpty); | ||
|
|
||
| _writePigeonError(indent); | ||
|
|
||
| if (hasHostApi) { | ||
| _writeWrapResult(indent); | ||
| _writeWrapError(indent); | ||
|
|
@@ -718,7 +720,7 @@ private func nilOrValue<T>(_ value: Any?) -> T? { | |
| name: name, | ||
| parameters: parameters, | ||
| returnType: returnType, | ||
| errorTypeName: 'FlutterError', | ||
| errorTypeName: 'PigeonError', | ||
| isAsynchronous: true, | ||
| swiftFunction: swiftFunction, | ||
| getParameterName: _getSafeArgumentName, | ||
|
|
@@ -760,12 +762,12 @@ private func nilOrValue<T>(_ value: Any?) -> T? { | |
| indent.writeln('let message: String? = nilOrValue(listResponse[1])'); | ||
| indent.writeln('let details: String? = nilOrValue(listResponse[2])'); | ||
| indent.writeln( | ||
| 'completion(.failure(FlutterError(code: code, message: message, details: details)))'); | ||
| 'completion(.failure(PigeonError(code: code, message: message, details: details)))'); | ||
| }, addTrailingNewline: false); | ||
| if (!returnType.isNullable && !returnType.isVoid) { | ||
| indent.addScoped('else if listResponse[0] == nil {', '} ', () { | ||
| indent.writeln( | ||
| 'completion(.failure(FlutterError(code: "null-error", message: "Flutter api returned null value for non-null return value.", details: "")))'); | ||
| 'completion(.failure(PigeonError(code: "null-error", message: "Flutter api returned null value for non-null return value.", details: "")))'); | ||
| }, addTrailingNewline: false); | ||
| } | ||
| indent.addScoped('else {', '}', () { | ||
|
|
@@ -895,6 +897,51 @@ private func nilOrValue<T>(_ value: Any?) -> T? { | |
| indent.writeln('$varChannelName.setMessageHandler(nil)'); | ||
| }); | ||
| } | ||
|
|
||
| void _writePigeonError(Indent indent) { | ||
| indent.newln(); | ||
| indent.writeln( | ||
| '/// Error thrown by Pigeon. Encapsulates a code, message, and details.'); | ||
| indent.writeln('class PigeonError: Swift.Error {'); | ||
| indent.nest(1, () { | ||
tarrinneal marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| indent.writeln('let code: String'); | ||
| indent.writeln('let message: String?'); | ||
| indent.writeln('let details: Any?'); | ||
| indent.newln(); | ||
| indent.writeln('init(code: String, message: String?, details: Any?) {'); | ||
| indent.nest(1, () { | ||
| indent.writeln('self.code = code'); | ||
| indent.writeln('self.message = message'); | ||
| indent.writeln('self.details = details'); | ||
| }); | ||
| indent.writeln('}'); | ||
| indent.newln(); | ||
| indent.writeln('var localizedDescription: String {'); | ||
| indent.nest(1, () { | ||
| indent.writeln('let detailsDescription: String'); | ||
| indent.writeln( | ||
| 'if let convertibleObject = details as? CustomStringConvertible {'); | ||
| indent.nest(1, () { | ||
| indent.writeln('detailsDescription = convertibleObject.description'); | ||
| }); | ||
| indent.writeln('} else if let _ = details {'); | ||
| indent.nest(1, () { | ||
| indent.writeln('detailsDescription = "<non-convertible object>"'); | ||
| }); | ||
| indent.writeln('} else {'); | ||
| indent.nest(1, () { | ||
| indent.writeln('detailsDescription = "<nil>"'); | ||
| }); | ||
| indent.writeln('}'); | ||
| indent.writeln( | ||
| r'return "PigeonError(code: \(code), message: \(message ?? "<nil>"), details: \(detailsDescription)"'); | ||
| }); | ||
| indent.write('}'); | ||
| }); | ||
| indent.newln(); | ||
| indent.write('}'); | ||
| indent.newln(); | ||
| } | ||
| } | ||
|
|
||
| /// Calculates the name of the codec that will be generated for [api]. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit:
final class PigeonError: Error