From 00ce5624e9b564cab2efeeec86e7e28a654e68c1 Mon Sep 17 00:00:00 2001 From: "Alkenso (Vladimir Vashurkin)" Date: Sat, 19 Mar 2022 21:13:46 +0200 Subject: [PATCH] Improved ObjC interop utils --- .../SwiftConvenience/ObjC Bridging/ObjC.swift | 46 +++++++++++++++++-- .../Extensions - Process.swift | 2 +- .../SwiftConvenienceObjC.h | 11 ++--- .../SwiftConvenienceObjC.m | 20 +++----- Tests/SwiftConvenienceTests/ObjCTests.swift | 25 ++++++++-- 5 files changed, 74 insertions(+), 30 deletions(-) diff --git a/Sources/SwiftConvenience/ObjC Bridging/ObjC.swift b/Sources/SwiftConvenience/ObjC Bridging/ObjC.swift index 2e97147..3db22ef 100644 --- a/Sources/SwiftConvenience/ObjC Bridging/ObjC.swift +++ b/Sources/SwiftConvenience/ObjC Bridging/ObjC.swift @@ -23,16 +23,54 @@ import Foundation @_implementationOnly import SwiftConvenienceObjC - extension NSException { - public static func catching(_ body: () -> Void) -> NSException? { - scbridge_catching(body) + public static func catching(_ body: () -> R) -> NSExceptionResult { + var result: NSExceptionResult! + if let exception = SwiftConvenienceObjC.nsException_catching({ + let value = body() + result = .success(value) + }) { + result = .exception(exception) + } + return result } } extension NSXPCConnection { public var auditToken: audit_token_t { - scbridge_auditToken + SwiftConvenienceObjC.nsxpcConnection_auditToken(self) + } +} + +public enum NSExceptionResult { + case success(Success) + case exception(NSException) +} + +extension NSExceptionResult { + public var success: Success? { + if case let .success(value) = self { + return value + } else { + return nil + } + } + + public var exception: NSException? { + if case let .exception(value) = self { + return value + } else { + return nil + } + } + + public func mapToResult(exceptionTransform: (NSException) -> Failure) -> Result { + switch self { + case .success(let success): + return .success(success) + case .exception(let exception): + return .failure(exceptionTransform(exception)) + } } } diff --git a/Sources/SwiftConvenience/System & Hardware/Extensions - Process.swift b/Sources/SwiftConvenience/System & Hardware/Extensions - Process.swift index 5340217..213fa0d 100644 --- a/Sources/SwiftConvenience/System & Hardware/Extensions - Process.swift +++ b/Sources/SwiftConvenience/System & Hardware/Extensions - Process.swift @@ -40,7 +40,7 @@ public extension Process { proc.standardOutput = standardOutPipe.fileHandleForWriting proc.standardError = standardErrPipe.fileHandleForWriting - if let exception = NSException.catching({ proc.launch() }) { + if let exception = NSException.catching({ proc.launch() }).exception { return ( ENOENT, "", diff --git a/Sources/SwiftConvenienceObjC/SwiftConvenienceObjC.h b/Sources/SwiftConvenienceObjC/SwiftConvenienceObjC.h index 7769ca4..546b57d 100644 --- a/Sources/SwiftConvenienceObjC/SwiftConvenienceObjC.h +++ b/Sources/SwiftConvenienceObjC/SwiftConvenienceObjC.h @@ -25,16 +25,11 @@ NS_ASSUME_NONNULL_BEGIN -@interface NSException (SwiftConvenience) +@interface SwiftConvenienceObjC : NSObject -+ (nullable instancetype)scbridge_catching:(void(NS_NOESCAPE ^)(void))block; ++ (nullable NSException *)NSException_catching:(void(NS_NOESCAPE ^)(void))block; -@end - - -@interface NSXPCConnection (SwiftConvenience) - -@property (nonatomic, readonly) audit_token_t scbridge_auditToken; ++ (audit_token_t)NSXPCConnection_auditToken:(NSXPCConnection *)connection; @end diff --git a/Sources/SwiftConvenienceObjC/SwiftConvenienceObjC.m b/Sources/SwiftConvenienceObjC/SwiftConvenienceObjC.m index 32b2eec..b5f8a7a 100644 --- a/Sources/SwiftConvenienceObjC/SwiftConvenienceObjC.m +++ b/Sources/SwiftConvenienceObjC/SwiftConvenienceObjC.m @@ -22,10 +22,13 @@ #import "SwiftConvenienceObjC.h" +@interface NSXPCConnection (SwiftConveniencePrivate) +@property (nonatomic, readonly) audit_token_t auditToken; +@end -@implementation NSException (SwiftConvenience) +@implementation SwiftConvenienceObjC -+ (nullable instancetype)scbridge_catching:(void(NS_NOESCAPE ^)(void))block ++ (nullable NSException *)NSException_catching:(void(NS_NOESCAPE ^)(void))block { @try { @@ -38,18 +41,9 @@ + (nullable instancetype)scbridge_catching:(void(NS_NOESCAPE ^)(void))block } } -@end - - -@interface NSXPCConnection (SwiftConveniencePrivate) -@property (nonatomic, readonly) audit_token_t auditToken; -@end - -@implementation NSXPCConnection (SwiftConvenience) - -- (audit_token_t)scbridge_auditToken ++ (audit_token_t)NSXPCConnection_auditToken:(NSXPCConnection *)connection { - return self.auditToken; + return connection.auditToken; } @end diff --git a/Tests/SwiftConvenienceTests/ObjCTests.swift b/Tests/SwiftConvenienceTests/ObjCTests.swift index 6120077..b0fa09d 100644 --- a/Tests/SwiftConvenienceTests/ObjCTests.swift +++ b/Tests/SwiftConvenienceTests/ObjCTests.swift @@ -10,11 +10,28 @@ import XCTest class ObjCTests: XCTestCase { - func test_catchNSException() throws { - let exception = NSException.catching { + func test_catchNSException_success() throws { + let result = NSException.catching { + return 10 + } + switch result { + case .success(let value): + XCTAssertEqual(value, 10) + case .exception: + XCTFail() + } + } + + func test_catchNSException_exception() throws { + let result = NSException.catching { NSException(name: .genericException, reason: "Just", userInfo: nil).raise() } - XCTAssertEqual(exception?.name, .genericException) - XCTAssertEqual(exception?.reason, "Just") + switch result { + case .success: + XCTFail() + case .exception(let exception): + XCTAssertEqual(exception.name, .genericException) + XCTAssertEqual(exception.reason, "Just") + } } }