From dc140c72b51fec82e17f8691e401fdc46d698673 Mon Sep 17 00:00:00 2001 From: Yehor Popovych Date: Thu, 23 Nov 2023 13:11:23 +0000 Subject: [PATCH] big code cleanup --- Examples/Rust/DApp/AlertProvider.swift | 9 +- Examples/Rust/Extension/NativeUI.swift | 6 +- Examples/Rust/Rust/Cargo.toml | 15 +++ Examples/Rust/Rust/app/Cargo.toml | 23 +++-- Examples/Rust/Rust/wallet/Cargo.toml | 22 ++--- Examples/Swift/DApp/AlertProvider.swift | 2 - Examples/Swift/DApp/AppCore.swift | 2 +- .../Protocols/SubstrateService.swift | 11 +-- .../Protocols/TestService.swift | 6 +- Sources/TesseractClient/Service.swift | 4 +- Sources/TesseractClient/Tesseract.swift | 8 +- .../TesseractClient/TesseractDelegate.swift | 6 +- Sources/TesseractService/Service.swift | 8 +- Sources/TesseractService/Tesseract.swift | 2 +- .../Protocols/SubstrateService.swift | 2 +- .../Protocols/TestService.swift | 2 +- .../CoreStatus.swift | 92 +++++++++++++++++ .../CoreTransport.swift | 99 +++---------------- .../TesseractTransportsClient/Transport.swift | 13 ++- .../iOS/IPCTransportIOS.swift | 2 +- .../CoreTransport.swift | 41 ++------ .../Transport.swift | 7 +- .../iOS/IPCTransportIOS.swift | 2 +- .../AutoFree+Error.swift | 18 ++++ .../CoreConvertible.swift | 17 ++++ Sources/TesseractUtils/AnyPtr.swift | 26 +++-- Sources/TesseractUtils/AutoFree.swift | 51 ++++++++++ Sources/TesseractUtils/Error.swift | 14 ++- Sources/TesseractUtils/Future.swift | 11 +-- Sources/TesseractUtils/FutureImpls.swift | 8 +- .../{SwiftPtr.swift => ObjectPtr.swift} | 24 ++--- Sources/TesseractUtils/Option.swift | 16 +-- Sources/TesseractUtils/Protocols.swift | 8 +- Sources/TesseractUtils/String.swift | 3 +- 34 files changed, 336 insertions(+), 244 deletions(-) create mode 100644 Sources/TesseractTransportsClient/CoreStatus.swift create mode 100644 Sources/TesseractTransportsShared/AutoFree+Error.swift create mode 100644 Sources/TesseractTransportsShared/CoreConvertible.swift create mode 100644 Sources/TesseractUtils/AutoFree.swift rename Sources/TesseractUtils/{SwiftPtr.swift => ObjectPtr.swift} (85%) diff --git a/Examples/Rust/DApp/AlertProvider.swift b/Examples/Rust/DApp/AlertProvider.swift index fdac8b4..9a650cd 100644 --- a/Examples/Rust/DApp/AlertProvider.swift +++ b/Examples/Rust/DApp/AlertProvider.swift @@ -6,11 +6,12 @@ // import Foundation +import TesseractTransportsShared import TesseractUtils import CApp -public class AlertProvider: ObservableObject { - public struct Alert: Identifiable { +public class AlertProvider: ObservableObject, CoreConvertible { + struct Alert: Identifiable { let message: String public var id: String { message } } @@ -22,7 +23,7 @@ public class AlertProvider: ObservableObject { self.alert = Alert(message: alert) } - func toCore() -> CApp.AlertProvider { + public func toCore() -> CApp.AlertProvider { var provider = CApp.AlertProvider(value: self) provider.show_alert = alert_provider_show_alert return provider @@ -36,6 +37,6 @@ private func alert_provider_show_alert(this: UnsafePointer!, } } -extension CApp.AlertProvider: CSwiftDropPtr { +extension CApp.AlertProvider: CObjectPtr { public typealias SObject = AlertProvider } diff --git a/Examples/Rust/Extension/NativeUI.swift b/Examples/Rust/Extension/NativeUI.swift index 4466dfe..df4a3b7 100644 --- a/Examples/Rust/Extension/NativeUI.swift +++ b/Examples/Rust/Extension/NativeUI.swift @@ -13,7 +13,7 @@ protocol NativeUIDelegate: AnyObject { func approveTx(tx: String) async -> Result } -extension CWallet.UI: CSwiftDropPtr { +extension CWallet.UI: CObjectPtr { public typealias SObject = NativeUI } @@ -24,7 +24,7 @@ extension CWallet.UI { } } -public class NativeUI { +public class NativeUI: CoreConvertible { weak var delegate: NativeUIDelegate! init(delegate: NativeUIDelegate) { @@ -35,7 +35,7 @@ public class NativeUI { await self.delegate.approveTx(tx: tx) } - func toCore() -> CWallet.UI { + public func toCore() -> CWallet.UI { CWallet.UI(ui: self) } } diff --git a/Examples/Rust/Rust/Cargo.toml b/Examples/Rust/Rust/Cargo.toml index 00dd0c1..e7d84de 100644 --- a/Examples/Rust/Rust/Cargo.toml +++ b/Examples/Rust/Rust/Cargo.toml @@ -7,6 +7,21 @@ members = [ "wallet" ] +[workspace.dependencies] +tesseract = { git = "https://github.com/tesseract-one/Tesseract.rs.git", branch = "dapp-fixes" } +tesseract-protocol-test = { git = "https://github.com/tesseract-one/Tesseract.rs.git", branch = "dapp-fixes" } +#tesseract = { path = "../../../../Tesseract.rs/tesseract", features = ["client"] } +#tesseract-protocol-test = { path = "../../../../Tesseract.rs/protocols/test", features = ["client"] } + +tesseract-swift-utils = { path = "../../../Rust/utils" } +tesseract-swift-transports = { path = "../../../Rust/transports" } +async-trait = "0.1" +errorcon = "0.1" +log = "0.4" +log-panics = { version = "2", features = ["with-backtrace"]} +stderrlog = "0.5" +cbindgen = "0.26" + [profile.release] strip = true lto = true \ No newline at end of file diff --git a/Examples/Rust/Rust/app/Cargo.toml b/Examples/Rust/Rust/app/Cargo.toml index d0f30e5..b15dac9 100644 --- a/Examples/Rust/Rust/app/Cargo.toml +++ b/Examples/Rust/Rust/app/Cargo.toml @@ -8,20 +8,19 @@ keywords = [ "Tesseract", "Cardano", "C" ] edition = "2021" [dependencies] -tesseract-swift-utils = { path = "../../../../Rust/utils" } -tesseract-swift-transports = { path = "../../../../Rust/transports", features = ["client"]} -#tesseract = { path = "../../../../../Tesseract.rs/tesseract", features = ["client"] } -#tesseract-protocol-test = { path = "../../../../../Tesseract.rs/protocols/test", features = ["client"] } -tesseract = { git = "https://github.com/tesseract-one/Tesseract.rs", branch = "master", features = ["client"] } -tesseract-protocol-test = { git = "https://github.com/tesseract-one/Tesseract.rs", branch = "master", features = ["client"] } -async-trait = "0.1" -errorcon = "0.1" -log = "0.4" -log-panics = { version = "2", features = ["with-backtrace"]} -stderrlog = "0.5" +tesseract-swift-utils.workspace = true +tesseract-swift-transports = { workspace = true, features = ["client"]} + +tesseract = { workspace = true, features = ["client"] } +tesseract-protocol-test = { workspace = true, features = ["client"] } +async-trait.workspace = true +errorcon.workspace = true +log.workspace = true +log-panics.workspace = true +stderrlog.workspace = true [build-dependencies] -cbindgen = "0.26" +cbindgen.workspace = true [lib] name = "app" diff --git a/Examples/Rust/Rust/wallet/Cargo.toml b/Examples/Rust/Rust/wallet/Cargo.toml index bec74de..1eaa179 100644 --- a/Examples/Rust/Rust/wallet/Cargo.toml +++ b/Examples/Rust/Rust/wallet/Cargo.toml @@ -8,20 +8,18 @@ keywords = [ "Tesseract", "Cardano", "C" ] edition = "2021" [dependencies] -tesseract-swift-utils = { path = "../../../../Rust/utils" } -tesseract-swift-transports = { path = "../../../../Rust/transports", features = ["service"]} -#tesseract = { path = "../../../../../Tesseract.rs/tesseract", features = ["service"] } -#tesseract-protocol-test = { path = "../../../../../Tesseract.rs/protocols/test", features = ["service"] } -tesseract = { git = "https://github.com/tesseract-one/Tesseract.rs", branch = "master", features = ["service"] } -tesseract-protocol-test = { git = "https://github.com/tesseract-one/Tesseract.rs", branch = "master", features = ["service"] } -async-trait = "0.1" -errorcon = "0.1" -log = "0.4" -log-panics = { version = "2", features = ["with-backtrace"]} -stderrlog = "0.5" +tesseract-swift-utils.workspace = true +tesseract-swift-transports = { workspace = true, features = ["service"]} +tesseract = { workspace = true, features = ["service"] } +tesseract-protocol-test = { workspace = true, features = ["service"] } +async-trait.workspace = true +errorcon.workspace = true +log.workspace = true +log-panics.workspace = true +stderrlog.workspace = true [build-dependencies] -cbindgen = "0.26" +cbindgen.workspace = true [lib] name = "wallet" diff --git a/Examples/Swift/DApp/AlertProvider.swift b/Examples/Swift/DApp/AlertProvider.swift index 7d49ae8..0b9578c 100644 --- a/Examples/Swift/DApp/AlertProvider.swift +++ b/Examples/Swift/DApp/AlertProvider.swift @@ -6,8 +6,6 @@ // import Foundation -import TesseractUtils -import CApp final class AlertProvider: ObservableObject { public struct Alert: Identifiable { diff --git a/Examples/Swift/DApp/AppCore.swift b/Examples/Swift/DApp/AppCore.swift index 825683a..9c31ce8 100644 --- a/Examples/Swift/DApp/AppCore.swift +++ b/Examples/Swift/DApp/AppCore.swift @@ -15,7 +15,7 @@ final class TesseractTransportDelegate: TesseractDelegate { self.alerts = alerts } - func select(transports: Dictionary) async -> String? { + func select(transports: Dictionary) async -> String? { assert(transports.count == 1, "How the heck do we have more than one transport here?") let transport = transports.first! switch transport.value { diff --git a/Sources/TesseractClient/Protocols/SubstrateService.swift b/Sources/TesseractClient/Protocols/SubstrateService.swift index 85142e0..43f0b3e 100644 --- a/Sources/TesseractClient/Protocols/SubstrateService.swift +++ b/Sources/TesseractClient/Protocols/SubstrateService.swift @@ -15,9 +15,9 @@ public final class SubstrateService: ServiceBase, public func getAccount( type: TesseractShared.SubstrateAccountType ) async throws -> TesseractShared.SubstrateGetAccountResponse { - try await withUnsafePointer(to: &service) { - $0.pointee.get_account($0, type.asCValue) - }.result.castError(TesseractError.self).get() + try await service.get_account(&service, type.asCValue) + .result + .castError(TesseractError.self).get() } public func signTransaction( @@ -27,9 +27,8 @@ public final class SubstrateService: ServiceBase, try await extrinsic.withPtrRef { ext in metadata.withPtrRef { meta in types.withPtrRef { types in - withUnsafePointer(to: &service) { - $0.pointee.sign_transaction($0, type.asCValue, path, ext, meta, types) - } + service.sign_transaction(&service, type.asCValue, + path, ext, meta, types) } } }.result.castError(TesseractError.self).get() diff --git a/Sources/TesseractClient/Protocols/TestService.swift b/Sources/TesseractClient/Protocols/TestService.swift index 3017e13..0592d14 100644 --- a/Sources/TesseractClient/Protocols/TestService.swift +++ b/Sources/TesseractClient/Protocols/TestService.swift @@ -13,9 +13,9 @@ public final class TestService: ServiceBase, TesseractShared.TestService { public func signTransaction(req: String) async throws -> String { - try await withUnsafePointer(to: &service) { - $0.pointee.sign_transaction($0, req) - }.result.castError(TesseractError.self).get() + try await service.sign_transaction(&service, req) + .result + .castError(TesseractError.self).get() } } diff --git a/Sources/TesseractClient/Service.swift b/Sources/TesseractClient/Service.swift index 2e950c9..325a14e 100644 --- a/Sources/TesseractClient/Service.swift +++ b/Sources/TesseractClient/Service.swift @@ -13,7 +13,7 @@ public protocol Service: AnyObject { init(tesseract: UnsafePointer) } -public protocol CoreService: CSwiftAnyDropPtr { +public protocol CoreService: CAnyObjectPtr { static func get(from tesseract: UnsafePointer) -> Self } @@ -25,6 +25,6 @@ open class ServiceBase: Service { } deinit { - try! service.free().get() + service.free() } } diff --git a/Sources/TesseractClient/Tesseract.swift b/Sources/TesseractClient/Tesseract.swift index 945e163..044a651 100644 --- a/Sources/TesseractClient/Tesseract.swift +++ b/Sources/TesseractClient/Tesseract.swift @@ -18,16 +18,16 @@ import CTesseract public final class Tesseract: TesseractBase { public private(set) var tesseract: ClientTesseract! - public init(delegate: TesseractDelegate, serializer: Serializer = .default) throws { + public init(delegate: any TesseractDelegate, serializer: Serializer = .default) throws { try super.init() tesseract = tesseract_client_new(delegate.toCore(), serializer.toCore()) } public func service(_ service: S.Type) -> S { - withUnsafePointer(to: &tesseract) { service.init(tesseract: $0) } + service.init(tesseract: &tesseract) } - public func transport(_ transport: T) -> Self { + public func transport>(_ transport: T) -> Self { tesseract = tesseract_client_add_transport(&tesseract, transport.toCore()) return self } @@ -38,7 +38,7 @@ public final class Tesseract: TesseractBase { } public static func `default`( - delegate: TesseractDelegate = SingleTransportDelegate(), + delegate: any TesseractDelegate = SingleTransportDelegate(), serializer: Serializer = .default ) throws -> Self { #if os(iOS) diff --git a/Sources/TesseractClient/TesseractDelegate.swift b/Sources/TesseractClient/TesseractDelegate.swift index df0066a..78ad07d 100644 --- a/Sources/TesseractClient/TesseractDelegate.swift +++ b/Sources/TesseractClient/TesseractDelegate.swift @@ -12,7 +12,7 @@ import TesseractShared @_exported import TesseractTransportsClient #endif -public protocol TesseractDelegate: AnyObject { +public protocol TesseractDelegate: AnyObject, CoreConvertible { func select(transports: Dictionary) async -> String? } @@ -24,7 +24,7 @@ public extension TesseractDelegate { } } -extension ClientTesseractDelegate: CSwiftAnyDropPtr {} +extension ClientTesseractDelegate: CAnyObjectPtr {} extension CKeyValue_CString__ClientStatus: CKeyValue, CPtr { public typealias CKey = CString @@ -56,7 +56,7 @@ private func delegate_select_transport( ) -> CFutureString { let trans: Dictionary = transports.copiedDictionary() return CFutureString { - await this.unowned(TesseractDelegate.self).castError().asyncFlatMap { + await this.unowned((any TesseractDelegate).self).castError().asyncFlatMap { guard let result = await $0.select(transports: trans) else { return .failure(TesseractError.cancelled) } diff --git a/Sources/TesseractService/Service.swift b/Sources/TesseractService/Service.swift index 368ec0b..11990e2 100644 --- a/Sources/TesseractService/Service.swift +++ b/Sources/TesseractService/Service.swift @@ -9,12 +9,8 @@ import Foundation import CTesseract import TesseractShared -public protocol Service: AnyObject { - associatedtype Core: CoreService - - func toCore() -> Core -} +public protocol Service: AnyObject, CoreConvertible where Core: CoreService {} -public protocol CoreService: CSwiftAnyDropPtr { +public protocol CoreService: CAnyObjectPtr { func register(in tesseract: UnsafeMutablePointer) -> ServiceTesseract } diff --git a/Sources/TesseractService/Tesseract.swift b/Sources/TesseractService/Tesseract.swift index 118ed15..cd7af5b 100644 --- a/Sources/TesseractService/Tesseract.swift +++ b/Sources/TesseractService/Tesseract.swift @@ -28,7 +28,7 @@ public final class Tesseract: TesseractBase { return self } - public func transport(_ transport: T) -> Self { + public func transport>(_ transport: T) -> Self { tesseract = tesseract_service_add_transport(&tesseract, transport.toCore()) return self } diff --git a/Sources/TesseractShared/Protocols/SubstrateService.swift b/Sources/TesseractShared/Protocols/SubstrateService.swift index 8984279..6a7ce70 100644 --- a/Sources/TesseractShared/Protocols/SubstrateService.swift +++ b/Sources/TesseractShared/Protocols/SubstrateService.swift @@ -69,7 +69,7 @@ public extension SubstrateService { } } -extension CTesseract.SubstrateService: CSwiftAnyDropPtr {} +extension CTesseract.SubstrateService: CAnyObjectPtr {} extension CTesseract.SubstrateAccountType: CType { public init() { self.init(0) } diff --git a/Sources/TesseractShared/Protocols/TestService.swift b/Sources/TesseractShared/Protocols/TestService.swift index 46c7eff..7a1c357 100644 --- a/Sources/TesseractShared/Protocols/TestService.swift +++ b/Sources/TesseractShared/Protocols/TestService.swift @@ -25,4 +25,4 @@ public extension TestService { } } -extension CTesseract.TestService: CSwiftAnyDropPtr {} +extension CTesseract.TestService: CAnyObjectPtr {} diff --git a/Sources/TesseractTransportsClient/CoreStatus.swift b/Sources/TesseractTransportsClient/CoreStatus.swift new file mode 100644 index 0000000..af572ad --- /dev/null +++ b/Sources/TesseractTransportsClient/CoreStatus.swift @@ -0,0 +1,92 @@ +// +// CoreStatus.swift +// +// +// Created by Yehor Popovych on 23/11/2023. +// + +import Foundation +import CTesseractShared +#if COCOAPODS +@_exported import TesseractShared +#else +@_exported import TesseractTransportsShared +#endif + +extension ClientStatus: CPtr, CType { + public typealias Val = Status + + public func copied() -> Status { + switch tag { + case ClientStatus_Ready: return .ready + case ClientStatus_Error: + return .error(TesseractError(cError: self.error.copied())) + case ClientStatus_Unavailable: + return .unavailable(self.unavailable.copied()) + default: fatalError("Unknown tag: \(tag)") + } + } + + public mutating func owned() -> Status { + switch tag { + case ClientStatus_Ready: return .ready + case ClientStatus_Error: + return .error(TesseractError(cError: self.error.owned())) + case ClientStatus_Unavailable: + return .unavailable(self.unavailable.owned()) + default: fatalError("Unknown tag: \(tag)") + } + } + + public mutating func free() { + switch tag { + case ClientStatus_Error: self.error.free() + case ClientStatus_Unavailable: self.unavailable.free() + default: break + } + } +} + +extension Status: AsCPtrCopy { + public typealias CopyPtr = ClientStatus + + public func copiedPtr() -> CopyPtr { + var cvalue = CopyPtr() + switch self { + case .ready: + cvalue.tag = ClientStatus_Ready + case .error(let err): + cvalue.tag = ClientStatus_Error + cvalue.error = err.cError.copiedPtr() + case .unavailable(let str): + cvalue.tag = ClientStatus_Unavailable + cvalue.unavailable = str.copiedPtr() + } + return cvalue + } +} + +extension Status: CoreConvertible { + public func toCore() -> ClientStatus { copiedPtr() } +} + +extension CFutureClientStatus: CFuturePtr { + public typealias CVal = ClientStatus + public typealias SVal = Status + + mutating public func _onComplete(cb: @escaping (CResult) -> Void) -> CResult? { + _withOnCompleteContext(cb) { ctx, value, error in + self.set_on_complete(&self, ctx, value, error) { ctx, val, err in + Self._onCompleteCallback(ctx, val, err) + } + } + } + + mutating public func _setupSetOnCompleteFunc() { + self.set_on_complete = { this, ctx, value, error, cb in + Self._setOnCompleteFunc(this, ctx, value, error) { this, val, err in + cb?(this, val, err) + } + } + } +} diff --git a/Sources/TesseractTransportsClient/CoreTransport.swift b/Sources/TesseractTransportsClient/CoreTransport.swift index eb26ffe..d4727d4 100644 --- a/Sources/TesseractTransportsClient/CoreTransport.swift +++ b/Sources/TesseractTransportsClient/CoreTransport.swift @@ -13,89 +13,17 @@ import CTesseractShared @_exported import TesseractTransportsShared #endif -public protocol CoreTransportConvertible { - func toCore() -> ClientTransport -} - -extension ClientStatus: CPtr, CType { - public typealias Val = Status - - public func copied() -> Status { - switch tag { - case ClientStatus_Ready: return .ready - case ClientStatus_Error: - return .error(TesseractError(cError: self.error.copied())) - case ClientStatus_Unavailable: - return .unavailable(self.unavailable.copied()) - default: fatalError("Unknown tag: \(tag)") - } - } - - public mutating func owned() -> Status { - switch tag { - case ClientStatus_Ready: return .ready - case ClientStatus_Error: - return .error(TesseractError(cError: self.error.owned())) - case ClientStatus_Unavailable: - return .unavailable(self.unavailable.owned()) - default: fatalError("Unknown tag: \(tag)") - } - } - - public mutating func free() { - switch tag { - case ClientStatus_Error: self.error.free() - case ClientStatus_Unavailable: self.unavailable.free() - default: break - } - } -} +public typealias CoreTransport = AutoFree & CoreConvertible -extension Status: AsCPtrCopy { - public typealias CopyPtr = ClientStatus - - public func copiedPtr() -> CopyPtr { - var cvalue = CopyPtr() - switch self { - case .ready: - cvalue.tag = ClientStatus_Ready - case .error(let err): - cvalue.tag = ClientStatus_Error - cvalue.error = err.cError.copiedPtr() - case .unavailable(let str): - cvalue.tag = ClientStatus_Unavailable - cvalue.unavailable = str.copiedPtr() - } - return cvalue - } -} - -extension CFutureClientStatus: CFuturePtr { - public typealias CVal = ClientStatus - public typealias SVal = Status - - mutating public func _onComplete(cb: @escaping (CResult) -> Void) -> CResult? { - _withOnCompleteContext(cb) { ctx, value, error in - self.set_on_complete(&self, ctx, value, error) { ctx, val, err in - Self._onCompleteCallback(ctx, val, err) - } - } - } - - mutating public func _setupSetOnCompleteFunc() { - self.set_on_complete = { this, ctx, value, error, cb in - Self._setOnCompleteFunc(this, ctx, value, error) { this, val, err in - cb?(this, val, err) - } - } - } +public extension AutoFree where Ptr == ClientTransport { + func toCore() -> ClientTransport { take() } } -extension ClientTransport: CSwiftAnyDropPtr {} -extension ClientConnection: CSwiftAnyDropPtr {} +extension ClientTransport: CAnyObjectPtr {} +extension ClientConnection: CAnyObjectPtr {} private func transport_id(self: UnsafePointer!) -> CString { - try! self.unowned(Transport.self).get().id.copiedPtr() + try! self.unowned((any Transport).self).get().id.copiedPtr() } private func transport_status( @@ -104,7 +32,7 @@ private func transport_status( ) -> CFutureClientStatus { let proto = proto.copied() return CFutureClientStatus { - await self.unowned(Transport.self).asyncFlatMap { + await self.unowned((any Transport).self).asyncFlatMap { .success(await $0.status(proto: proto)) } } @@ -114,7 +42,8 @@ private func transport_connect( self: UnsafePointer!, proto: CStringRef! ) -> ClientConnection { - try! self.unowned(Transport.self).get().connect(proto: proto.copied()).toCore() + try! self.unowned((any Transport).self) + .get().connect(proto: proto.copied()).toCore() } private func connection_send(self: UnsafePointer!, @@ -122,7 +51,7 @@ private func connection_send(self: UnsafePointer!, { let data = data.copied() return CFutureNothing { - await self.unowned(Connection.self).castError().asyncFlatMap { + await self.unowned((any Connection).self).castError().asyncFlatMap { await $0.send(request: data) } } @@ -130,14 +59,14 @@ private func connection_send(self: UnsafePointer!, private func connection_receive(self: UnsafePointer!) -> CFutureData { return CFutureData { - await self.unowned(Connection.self).castError().asyncFlatMap { + await self.unowned((any Connection).self).castError().asyncFlatMap { await $0.receive() } } } extension ClientTransport { - public init(transport: Transport) { + public init(transport: any Transport) { self = Self(value: transport) self.id = transport_id self.status = transport_status @@ -146,14 +75,14 @@ extension ClientTransport { } extension ClientConnection { - public init(connection: Connection) { + public init(connection: any Connection) { self = Self(value: connection) self.send = connection_send self.receive = connection_receive } } -extension ClientTransport: CoreTransportConvertible { +extension ClientTransport: CoreConvertible { public func toCore() -> ClientTransport { self } } diff --git a/Sources/TesseractTransportsClient/Transport.swift b/Sources/TesseractTransportsClient/Transport.swift index 85fd600..7909236 100644 --- a/Sources/TesseractTransportsClient/Transport.swift +++ b/Sources/TesseractTransportsClient/Transport.swift @@ -6,6 +6,7 @@ // import Foundation +import CTesseractShared #if COCOAPODS import TesseractShared #else @@ -16,10 +17,8 @@ public enum Status { case ready case unavailable(String) case error(TesseractError) -} - -public extension Status { - var isReady: Bool { + + public var isReady: Bool { switch self { case .ready: return true default: return false @@ -27,13 +26,13 @@ public extension Status { } } -public protocol Connection: AnyObject { +public protocol Connection: AnyObject, CoreConvertible { func send(request: Data) async -> Result<(), TesseractError> func receive() async -> Result } -public protocol Transport: AnyObject, CoreTransportConvertible { +public protocol Transport: AnyObject, CoreConvertible { var id: String { get } func status(proto: String) async -> Status - func connect(proto: String) -> Connection + func connect(proto: String) -> any Connection } diff --git a/Sources/TesseractTransportsClient/iOS/IPCTransportIOS.swift b/Sources/TesseractTransportsClient/iOS/IPCTransportIOS.swift index c9f4a7b..595c40f 100644 --- a/Sources/TesseractTransportsClient/iOS/IPCTransportIOS.swift +++ b/Sources/TesseractTransportsClient/iOS/IPCTransportIOS.swift @@ -66,7 +66,7 @@ public class IPCTransportIOS: Transport { } } - public func connect(proto: String) -> Connection { + public func connect(proto: String) -> any Connection { TransportConnection(proto: proto, presenter: presenter) } diff --git a/Sources/TesseractTransportsService/CoreTransport.swift b/Sources/TesseractTransportsService/CoreTransport.swift index d25bc50..5723524 100644 --- a/Sources/TesseractTransportsService/CoreTransport.swift +++ b/Sources/TesseractTransportsService/CoreTransport.swift @@ -13,50 +13,29 @@ import CTesseractShared @_exported import TesseractTransportsShared #endif -public protocol CoreTransportConvertible { - func toCore() -> ServiceTransport -} +public typealias CoreTransport = AutoFree & CoreConvertible -open class CoreTransportBase: CoreTransportConvertible { - public private(set) var core: ServiceTransport! - - public init( - initializer: (UnsafeMutablePointer, - UnsafeMutablePointer) -> Bool - ) throws { - self.core = try CResult - .wrap(ccall: initializer) - .castError(TesseractError.self) - .get() - } - - deinit { - if core != nil { try! core.free().get() } - } - - public func toCore() -> ServiceTransport { - defer { core = nil } - return core - } +public extension AutoFree where Ptr == ServiceTransport { + func toCore() -> ServiceTransport { take() } } -extension ServiceTransport: CSwiftAnyDropPtr {} +extension ServiceTransport: CAnyObjectPtr {} extension ServiceTransport { - public init(transport: Transport) { + public init(transport: any Transport) { self = ServiceTransport(value: transport) self.bind = transport_bind } } -extension Transport { - public func toCore() -> ServiceTransport { +public extension Transport { + func toCore() -> ServiceTransport { ServiceTransport(transport: self) } } -extension BoundTransport { - public func toCore() -> ServiceBoundTransport { +public extension BoundTransport { + func toCore() -> ServiceBoundTransport { ServiceBoundTransport(value: self) } } @@ -65,7 +44,7 @@ private func transport_bind(this: ServiceTransport, processor: ServiceTransportProcessor) -> ServiceBoundTransport { var this = this - return try! this.owned(Transport.self).get() + return try! this.owned((any Transport).self).get() .bind(processor: TransportProcessor(processor: processor)) .toCore() } diff --git a/Sources/TesseractTransportsService/Transport.swift b/Sources/TesseractTransportsService/Transport.swift index bbe40af..705a09a 100644 --- a/Sources/TesseractTransportsService/Transport.swift +++ b/Sources/TesseractTransportsService/Transport.swift @@ -6,14 +6,15 @@ // import Foundation +import CTesseractShared #if COCOAPODS import TesseractShared #else import TesseractTransportsShared #endif -public protocol BoundTransport: AnyObject {} +public protocol BoundTransport: CoreConvertible, AnyObject {} -public protocol Transport: CoreTransportConvertible, AnyObject { - func bind(processor: TransportProcessor) -> BoundTransport +public protocol Transport: CoreConvertible, AnyObject { + func bind(processor: TransportProcessor) -> any BoundTransport } diff --git a/Sources/TesseractTransportsService/iOS/IPCTransportIOS.swift b/Sources/TesseractTransportsService/iOS/IPCTransportIOS.swift index 9b1484b..d2cea59 100644 --- a/Sources/TesseractTransportsService/iOS/IPCTransportIOS.swift +++ b/Sources/TesseractTransportsService/iOS/IPCTransportIOS.swift @@ -158,7 +158,7 @@ extension IPCTransportIOS { } extension IPCTransportIOS: Transport { - public func bind(processor: TransportProcessor) -> BoundTransport { + public func bind(processor: TransportProcessor) -> any BoundTransport { Bound(transport: self, processor: processor) } } diff --git a/Sources/TesseractTransportsShared/AutoFree+Error.swift b/Sources/TesseractTransportsShared/AutoFree+Error.swift new file mode 100644 index 0000000..07ccc9f --- /dev/null +++ b/Sources/TesseractTransportsShared/AutoFree+Error.swift @@ -0,0 +1,18 @@ +// +// AutoFree+Error.swift +// +// +// Created by Yehor Popovych on 23/11/2023. +// + +import Foundation +import CTesseractShared + +public extension AutoFree { + convenience init( + initializer: (UnsafeMutablePointer, + UnsafeMutablePointer) -> Bool + ) throws { + try self.init(error: TesseractError.self, initializer: initializer) + } +} diff --git a/Sources/TesseractTransportsShared/CoreConvertible.swift b/Sources/TesseractTransportsShared/CoreConvertible.swift new file mode 100644 index 0000000..eab242e --- /dev/null +++ b/Sources/TesseractTransportsShared/CoreConvertible.swift @@ -0,0 +1,17 @@ +// +// CoreConvertible.swift +// +// +// Created by Yehor Popovych on 23/11/2023. +// + +import Foundation +#if !COCOAPODS +import TesseractUtils +#endif + +public protocol CoreConvertible { + associatedtype Core: CType + + func toCore() -> Core +} diff --git a/Sources/TesseractUtils/AnyPtr.swift b/Sources/TesseractUtils/AnyPtr.swift index 2340b81..c16915c 100644 --- a/Sources/TesseractUtils/AnyPtr.swift +++ b/Sources/TesseractUtils/AnyPtr.swift @@ -8,7 +8,17 @@ import Foundation import CTesseractShared -extension CAnyDropPtr: CType {} +extension CAnyRustPtr: CType, CFree { + public mutating func free() { + tesseract_utils_any_rust_ptr_free(&self) + } +} + +extension CAnyDropPtr: CType, CFree { + public mutating func free() { + (self.drop)(&self) + } +} extension CAnyDropPtr { public init(value: AnyObject) { @@ -55,22 +65,8 @@ extension CAnyDropPtr { return .success(typed) } } - - public mutating func free() -> CResult { - guard !self.isNull else { return .failure(.null(Self.self)) } - (self.drop)(&self) - return .success(()) - } } private func any_ptr_swift_drop(ptr: UnsafeMutablePointer!) { let _ = ptr.pointee.ptr.owned()! } - -extension CAnyRustPtr: CType {} - -extension CAnyRustPtr { - public mutating func free() { - tesseract_utils_any_rust_ptr_free(&self); - } -} diff --git a/Sources/TesseractUtils/AutoFree.swift b/Sources/TesseractUtils/AutoFree.swift new file mode 100644 index 0000000..6209d50 --- /dev/null +++ b/Sources/TesseractUtils/AutoFree.swift @@ -0,0 +1,51 @@ +// +// AutoFree.swift +// +// +// Created by Yehor Popovych on 23/11/2023. +// + +import Foundation +import CTesseractShared + +open class AutoFree { + private var _ptr: Ptr? + + public convenience init( + error: E.Type, + initializer: (UnsafeMutablePointer, + UnsafeMutablePointer) -> Bool + ) throws { + let ptr = try CResult.wrap(ccall: initializer).castError(error).get() + self.init(ptr: ptr) + } + + public init(ptr: Ptr) { + _ptr = ptr + } + + public func use(_ fn: (inout Ptr) throws -> R) rethrows -> R { + guard _ptr != nil else { fatalError("Null pointer: \(Ptr.self)") } + return try fn(&_ptr!) + } + + public func use(_ fn: (UnsafePointer) throws -> R) rethrows -> R { + guard _ptr != nil else { fatalError("Null pointer: \(Ptr.self)") } + return try fn(&_ptr!) + } + + public func use(_ fn: (UnsafeMutablePointer) throws -> R) rethrows -> R { + guard _ptr != nil else { fatalError("Null pointer: \(Ptr.self)") } + return try fn(&_ptr!) + } + + public func take() -> Ptr { + guard _ptr != nil else { fatalError("Null pointer: \(Ptr.self)") } + defer { _ptr = nil } + return _ptr! + } + + deinit { + if _ptr != nil { _ptr!.free() } + } +} diff --git a/Sources/TesseractUtils/Error.swift b/Sources/TesseractUtils/Error.swift index 5e8ba84..055cc1b 100644 --- a/Sources/TesseractUtils/Error.swift +++ b/Sources/TesseractUtils/Error.swift @@ -76,6 +76,11 @@ extension CError: CustomStringConvertible { } } +extension CError: CErrorInitializable, CErrorConvertible { + public init(cError: CError) { self = cError } + public var cError: CError { self } +} + extension CError: AsCPtrCopy { public typealias CopyPtr = CTesseractShared.CError @@ -180,11 +185,10 @@ extension NSError: AsCPtrRef { ) rethrows -> T { try domain.withPtrRef { domain in try self.localizedDescription.withPtrRef { description in - try withUnsafePointer( - to: CTesseractShared.SwiftError(code: self.code, - domain: domain.pointee, - description: description.pointee) - ) { try fn($0) } + var swift = CTesseractShared.SwiftError(code: self.code, + domain: domain.pointee, + description: description.pointee) + return try fn(&swift) } } } diff --git a/Sources/TesseractUtils/Future.swift b/Sources/TesseractUtils/Future.swift index 0ab8e06..7a9fbf6 100644 --- a/Sources/TesseractUtils/Future.swift +++ b/Sources/TesseractUtils/Future.swift @@ -8,7 +8,7 @@ import Foundation import CTesseractShared -public protocol CFuturePtr: CType { +public protocol CFuturePtr: CType, CFree { associatedtype CVal: CType associatedtype SVal @@ -17,9 +17,6 @@ public protocol CFuturePtr: CType { // Consumes future. Will call free automatically func onComplete(cb: @escaping (CResult) -> Void) -> CResult? - // Frees unconsumed future. Call it only if you don't want to use the future - mutating func free() -> CResult - // Helpers for value converting static func convert(cvalue: inout CVal) -> CResult static func convert(value: inout SVal) -> CResult @@ -91,7 +88,7 @@ extension CFuturePtr { } // Call it only if you don't want to wait for the Future. - public mutating func free() -> CResult { + public mutating func free() { self.ptr.free() } } @@ -258,7 +255,7 @@ extension CFuturePtr { if result != nil { // We have value already. Context is non needed var this = self let _ = CFutureContext.take(pointer) - try! this.free().get() + this.free() } return result } @@ -269,7 +266,7 @@ extension CFuturePtr { _ error: UnsafeMutablePointer? ) { var ctx = CFutureContext.take(ctx) - defer { try! ctx.future.free().get() } + defer { ctx.future.free() } if let error = error { ctx.callback(.failure(error.pointee.owned())) } else { diff --git a/Sources/TesseractUtils/FutureImpls.swift b/Sources/TesseractUtils/FutureImpls.swift index 9ca6514..fa937b9 100644 --- a/Sources/TesseractUtils/FutureImpls.swift +++ b/Sources/TesseractUtils/FutureImpls.swift @@ -40,7 +40,7 @@ extension CFutureNothing: CFuturePtr { extension CFutureAnyRustPtr: CFuturePtr { public typealias CVal = CAnyRustPtr public typealias SVal = CAnyRustPtr - + public mutating func _onComplete(cb: @escaping (CResult) -> Void) -> CResult? { _withOnCompleteContext(cb) { ctx, value, error in self.set_on_complete(&self, ctx, value, error) { ctx, val, err in @@ -48,7 +48,7 @@ extension CFutureAnyRustPtr: CFuturePtr { } } } - + public mutating func _setupSetOnCompleteFunc() { self.set_on_complete = { this, ctx, value, error, cb in Self._setOnCompleteFunc(this, ctx, value, error) { this, val, err in @@ -56,11 +56,11 @@ extension CFutureAnyRustPtr: CFuturePtr { } } } - + public static func convert(cvalue: inout CAnyRustPtr) -> CResult { .success(cvalue) } - + public static func convert(value: inout CAnyRustPtr) -> CResult { .success(value) } diff --git a/Sources/TesseractUtils/SwiftPtr.swift b/Sources/TesseractUtils/ObjectPtr.swift similarity index 85% rename from Sources/TesseractUtils/SwiftPtr.swift rename to Sources/TesseractUtils/ObjectPtr.swift index f516c70..d6b96b7 100644 --- a/Sources/TesseractUtils/SwiftPtr.swift +++ b/Sources/TesseractUtils/ObjectPtr.swift @@ -8,7 +8,7 @@ import Foundation import CTesseractShared -public protocol CSwiftDropPtr: CType { +public protocol CObjectPtr: CType, CFree { associatedtype SObject: AnyObject var ptr: CAnyDropPtr { get set } @@ -17,11 +17,9 @@ public protocol CSwiftDropPtr: CType { func unowned() -> CResult mutating func owned() -> CResult - - mutating func free() -> CResult } -extension CSwiftDropPtr { +extension CObjectPtr { public init(value object: SObject) { self = Self() self.ptr = .wrapped(object) @@ -35,12 +33,12 @@ extension CSwiftDropPtr { self.ptr.owned(SObject.self) } - public mutating func free() -> CResult { + public mutating func free() { self.ptr.free() } } -public protocol CSwiftAnyDropPtr: CType { +public protocol CAnyObjectPtr: CType, CFree { var ptr: CAnyDropPtr { get set } init(value object: AnyObject) @@ -50,11 +48,9 @@ public protocol CSwiftAnyDropPtr: CType { mutating func owned() -> CResult mutating func owned(_ type: T.Type) -> CResult - - mutating func free() -> CResult } -extension CSwiftAnyDropPtr { +extension CAnyObjectPtr { public init(value object: AnyObject) { self = Self() self.ptr = .wrapped(object) @@ -79,18 +75,18 @@ extension CSwiftAnyDropPtr { self.ptr.owned(type) } - public mutating func free() -> CResult { + public mutating func free() { self.ptr.free() } } -extension UnsafePointer where Pointee: CSwiftDropPtr { +extension UnsafePointer where Pointee: CObjectPtr { public func unowned() -> CResult { self.pointee.unowned() } } -extension UnsafeMutablePointer where Pointee: CSwiftDropPtr { +extension UnsafeMutablePointer where Pointee: CObjectPtr { public func unowned() -> CResult { self.pointee.unowned() } @@ -100,7 +96,7 @@ extension UnsafeMutablePointer where Pointee: CSwiftDropPtr { } } -extension UnsafePointer where Pointee: CSwiftAnyDropPtr { +extension UnsafePointer where Pointee: CAnyObjectPtr { public func unowned() -> CResult { self.pointee.unowned() } @@ -110,7 +106,7 @@ extension UnsafePointer where Pointee: CSwiftAnyDropPtr { } } -extension UnsafeMutablePointer where Pointee: CSwiftAnyDropPtr { +extension UnsafeMutablePointer where Pointee: CAnyObjectPtr { public func unowned() -> CResult { self.pointee.unowned() } diff --git a/Sources/TesseractUtils/Option.swift b/Sources/TesseractUtils/Option.swift index 685e3a7..dc31b42 100644 --- a/Sources/TesseractUtils/Option.swift +++ b/Sources/TesseractUtils/Option.swift @@ -19,6 +19,15 @@ extension Optional: CPtrRef where Wrapped: CPtrRef { } } +extension Optional: CFree where Wrapped: CFree { + public mutating func free() { + if var val = self { + val.free() + self = nil + } + } +} + extension Optional: CPtr where Wrapped: CPtr { public mutating func owned() -> SVal { switch self { @@ -29,13 +38,6 @@ extension Optional: CPtr where Wrapped: CPtr { return owned } } - - public mutating func free() { - if var val = self { - val.free() - self = nil - } - } } extension Optional: CValue where Wrapped: CValue { diff --git a/Sources/TesseractUtils/Protocols.swift b/Sources/TesseractUtils/Protocols.swift index 0bcbd8e..e653131 100644 --- a/Sources/TesseractUtils/Protocols.swift +++ b/Sources/TesseractUtils/Protocols.swift @@ -13,6 +13,11 @@ public protocol CType { init() } +// Type returned from C that should be deleted +public protocol CFree { + mutating func free() +} + // Ref structure with pointers inside public protocol CPtrRef { associatedtype SVal @@ -21,9 +26,8 @@ public protocol CPtrRef { } // Structure with pointers inside -public protocol CPtr: CPtrRef { +public protocol CPtr: CPtrRef, CFree { mutating func owned() -> SVal - mutating func free() } // Swift value which can be simply converted from C (static struct) diff --git a/Sources/TesseractUtils/String.swift b/Sources/TesseractUtils/String.swift index 72f5be1..38a2cf5 100644 --- a/Sources/TesseractUtils/String.swift +++ b/Sources/TesseractUtils/String.swift @@ -47,7 +47,8 @@ extension String: AsCPtrRef { _ fn: (UnsafePointer) throws -> T ) rethrows -> T { try withCString { - try withUnsafePointer(to: CString(_0: $0)) { try fn($0) } + var str = CString(_0: $0) + return try fn(&str) } } }