diff --git a/Examples/OCADevice/DeviceApp.swift b/Examples/OCADevice/DeviceApp.swift index 453bb6d3..c1c8996a 100644 --- a/Examples/OCADevice/DeviceApp.swift +++ b/Examples/OCADevice/DeviceApp.swift @@ -38,7 +38,7 @@ public enum DeviceApp { public static func main() async throws { var listenAddress = sockaddr_in() listenAddress.sin_family = sa_family_t(AF_INET) - listenAddress.sin_addr.s_addr = 0 // INADDR_ANY equivalent + listenAddress.sin_addr.s_addr = 0 // INADDR_ANY equivalent listenAddress.sin_port = port.bigEndian #if canImport(Darwin) || os(FreeBSD) || os(OpenBSD) listenAddress.sin_len = UInt8(MemoryLayout.size) @@ -61,7 +61,8 @@ public enum DeviceApp { } let delegate = DeviceEventDelegate() await device.setEventDelegate(delegate) - #if os(Linux) + + #if os(Linux) && NonEmbeddedBuild let streamEndpoint = try await Ocp1IORingStreamDeviceEndpoint(address: listenAddress.data) let datagramEndpoint = try await Ocp1IORingDatagramDeviceEndpoint(address: listenAddress.data) let stream6Endpoint = try await Ocp1IORingStreamDeviceEndpoint(address: listen6Address.data) @@ -70,7 +71,7 @@ public enum DeviceApp { try? await Ocp1IORingStreamDeviceEndpoint(path: "/tmp/oca-device.sock") let domainSocketDatagramEndpoint = try? await Ocp1IORingDatagramDeviceEndpoint(path: "/tmp/oca-device-dg.sock") - #elseif canImport(FlyingSocks) + #elseif canImport(FlyingSocks) && NonEmbeddedBuild let streamEndpoint = try await Ocp1FlyingSocksStreamDeviceEndpoint(address: listenAddress.data) let datagramEndpoint = try await Ocp1FlyingSocksDatagramDeviceEndpoint(address: listenAddress.data) @@ -87,9 +88,10 @@ public enum DeviceApp { #else let streamEndpoint = try await Ocp1StreamDeviceEndpoint(address: listenAddress.data) #endif - #if canImport(FlyingSocks) + + #if canImport(FlyingFox) && NonEmbeddedBuild listenAddress.sin_family = sa_family_t(AF_INET) - listenAddress.sin_addr.s_addr = 0 // INADDR_ANY equivalent + listenAddress.sin_addr.s_addr = 0 // INADDR_ANY equivalent listenAddress.sin_port = (port + 2).bigEndian #if canImport(Darwin) || os(FreeBSD) || os(OpenBSD) listenAddress.sin_len = UInt8(MemoryLayout.size) @@ -132,7 +134,9 @@ public enum DeviceApp { ) try await block.add(actionObject: gain) + #if NonEmbeddedBuild try await serializeDeserialize(device.rootBlock) + #endif let controlNetwork = try await SwiftOCADevice.OcaControlNetwork(deviceDelegate: device) Task { @OcaDevice in controlNetwork.state = .running } @@ -145,6 +149,7 @@ public enum DeviceApp { } } + #if NonEmbeddedBuild try await withThrowingTaskGroup(of: Void.self) { taskGroup in taskGroup.addTask { print("Starting OCP.1 IPv4 stream endpoint \(streamEndpoint)...") @@ -186,9 +191,14 @@ public enum DeviceApp { #endif try await taskGroup.next() } + #else + print("Starting OCP.1 IPv4 stream endpoint \(streamEndpoint)...") + try await streamEndpoint.run() + #endif } } +#if NonEmbeddedBuild func serializeDeserialize( _ object: SwiftOCADevice .OcaBlock @@ -203,3 +213,4 @@ func serializeDeserialize( debugPrint("serialization error: \(error)") } } +#endif diff --git a/Package.swift b/Package.swift index f0d34316..8e89a05a 100644 --- a/Package.swift +++ b/Package.swift @@ -15,16 +15,32 @@ if EnableASAN { ASANLinkerSettings.append(LinkerSetting.linkedLibrary("asan")) } -let PlatformPackageDependencies: [Package.Dependency] -let PlatformTargetDependencies: [Target.Dependency] +var PlatformPackageDependencies: [Package.Dependency] = [] +var PlatformTargetDependencies: [Target.Dependency] = [] let PlatformProducts: [Product] let PlatformTargets: [Target] let SwiftLanguageVersionSetting: [SwiftSetting] +PlatformPackageDependencies += [ + .package(url: "https://github.com/PADL/FlyingFox", branch: "main"), +] + +PlatformTargetDependencies += [ + .product( + name: "FlyingSocks", + package: "FlyingFox" + ), + .product( + name: "FlyingFox", + package: "FlyingFox", + condition: .when(traits: ["NonEmbeddedBuild"]) + ), +] + #if os(Linux) -PlatformPackageDependencies = [.package(url: "https://github.com/PADL/IORingSwift", from: "0.9.2")] +PlatformPackageDependencies += [.package(url: "https://github.com/PADL/IORingSwift", from: "0.9.2")] -PlatformTargetDependencies = [ +PlatformTargetDependencies += [ .target( name: "dnssd", condition: .when(platforms: [.linux]) @@ -32,17 +48,17 @@ PlatformTargetDependencies = [ .product( name: "IORing", package: "IORingSwift", - condition: .when(platforms: [.linux]) + condition: .when(platforms: [.linux], traits: ["NonEmbeddedBuild"]) ), .product( name: "IORingUtils", package: "IORingSwift", - condition: .when(platforms: [.linux]) + condition: .when(platforms: [.linux], traits: ["NonEmbeddedBuild"]) ), .product( name: "IORingFoundation", package: "IORingSwift", - condition: .when(platforms: [.linux]) + condition: .when(platforms: [.linux], traits: ["NonEmbeddedBuild"]) ), ] @@ -50,27 +66,13 @@ PlatformProducts = [] PlatformTargets = [] SwiftLanguageVersionSetting = [] #elseif os(macOS) || os(iOS) -PlatformPackageDependencies = [ - .package(url: "https://github.com/swhitty/FlyingFox", from: "0.20.0"), +PlatformPackageDependencies += [ .package( url: "https://github.com/spacenation/swiftui-sliders", from: "2.1.0" ), ] -PlatformTargetDependencies = [ - .product( - name: "FlyingFox", - package: "FlyingFox", - condition: .when(platforms: [.macOS, .iOS, .android]) - ), - .product( - name: "FlyingSocks", - package: "FlyingFox", - condition: .when(platforms: [.macOS, .iOS, .android]) - ), -] - PlatformProducts = [ .library( name: "SwiftOCAUI", @@ -147,7 +149,11 @@ let CommonTargets: [Target] = [ name: "SwiftOCA", dependencies: [ "AsyncExtensions", - "AnyCodable", + .product( + name: "AnyCodable", + package: "AnyCodable", + condition: .when(traits: ["NonEmbeddedBuild"]) + ), "SocketAddress", .product(name: "AsyncAlgorithms", package: "swift-async-algorithms"), .product(name: "SystemPackage", package: "swift-system"), @@ -233,6 +239,10 @@ let package = Package( .iOS(.v17), ], products: CommonProducts + PlatformProducts, + traits: [ + .default(enabledTraits: ["NonEmbeddedBuild"]), + .init(name: "NonEmbeddedBuild", description: "Default build footprint"), + ], dependencies: CommonPackageDependencies + PlatformPackageDependencies, targets: CommonTargets + PlatformTargets ) diff --git a/Sources/SwiftOCA/OCC/ControlClasses/Root+JSON.swift b/Sources/SwiftOCA/OCC/ControlClasses/Root+JSON.swift index 9d72a0e1..079200a9 100644 --- a/Sources/SwiftOCA/OCC/ControlClasses/Root+JSON.swift +++ b/Sources/SwiftOCA/OCC/ControlClasses/Root+JSON.swift @@ -14,6 +14,7 @@ // limitations under the License. // +#if NonEmbeddedBuild import AnyCodable #if canImport(FoundationEssentials) import FoundationEssentials @@ -37,3 +38,4 @@ enum OcaJSONPropertyKeys: String { case type case members } +#endif diff --git a/Sources/SwiftOCA/OCC/ControlClasses/Root.swift b/Sources/SwiftOCA/OCC/ControlClasses/Root.swift index d417e04a..69560415 100644 --- a/Sources/SwiftOCA/OCC/ControlClasses/Root.swift +++ b/Sources/SwiftOCA/OCC/ControlClasses/Root.swift @@ -134,6 +134,7 @@ open class OcaRoot: CustomStringConvertible, @unchecked Sendable, _OcaObjectKeyP } } + #if NonEmbeddedBuild open func getJsonValue( flags: OcaPropertyResolutionFlags = .defaultFlags ) async -> [String: any Sendable] { @@ -178,6 +179,7 @@ open class OcaRoot: CustomStringConvertible, @unchecked Sendable, _OcaObjectKeyP await getJsonValue(flags: .defaultFlags) } } + #endif public func propertyKeyPath(for propertyID: OcaPropertyID) async -> AnyKeyPath? { await OcaPropertyKeyPathCache.shared.lookupProperty(byID: propertyID, for: self) @@ -335,6 +337,7 @@ public extension OcaRoot { value } + #if NonEmbeddedBuild func getJsonValue( _ object: OcaRoot, keyPath: AnyKeyPath, @@ -342,6 +345,7 @@ public extension OcaRoot { ) async throws -> [String: any Sendable] { try [keyPath.jsonKey: String(describing: value)] } + #endif @_spi(SwiftOCAPrivate) public func _setValue(_ object: OcaRoot, _ anyValue: Any) async throws { diff --git a/Sources/SwiftOCA/OCC/ControlClasses/Workers/BlocksAndMatrices/Block.swift b/Sources/SwiftOCA/OCC/ControlClasses/Workers/BlocksAndMatrices/Block.swift index 07c00304..e31ffbea 100644 --- a/Sources/SwiftOCA/OCC/ControlClasses/Workers/BlocksAndMatrices/Block.swift +++ b/Sources/SwiftOCA/OCC/ControlClasses/Workers/BlocksAndMatrices/Block.swift @@ -507,6 +507,7 @@ Sendable { true } + #if NonEmbeddedBuild override open func getJsonValue( flags: OcaPropertyResolutionFlags = .defaultFlags ) async -> [String: any Sendable] { @@ -516,6 +517,7 @@ Sendable { .asyncMap { await $0.getJsonValue(flags: flags) } return jsonObject } + #endif } public extension OcaBlock { diff --git a/Sources/SwiftOCA/OCC/ControlClasses/Workers/BlocksAndMatrices/Matrix.swift b/Sources/SwiftOCA/OCC/ControlClasses/Workers/BlocksAndMatrices/Matrix.swift index cbb2f65b..7028f3ce 100644 --- a/Sources/SwiftOCA/OCC/ControlClasses/Workers/BlocksAndMatrices/Matrix.swift +++ b/Sources/SwiftOCA/OCC/ControlClasses/Workers/BlocksAndMatrices/Matrix.swift @@ -104,6 +104,7 @@ Sendable { true } + #if NonEmbeddedBuild override open func getJsonValue( flags: OcaPropertyResolutionFlags = .defaultFlags ) async -> [String: any Sendable] { @@ -113,6 +114,7 @@ Sendable { .reencodeAsValidJSONObject(membersJson) return jsonObject } + #endif } public extension OcaMatrix { diff --git a/Sources/SwiftOCA/OCC/PropertyTypes/BoundedProperty.swift b/Sources/SwiftOCA/OCC/PropertyTypes/BoundedProperty.swift index 2731c5f8..5a0d97b9 100644 --- a/Sources/SwiftOCA/OCC/PropertyTypes/BoundedProperty.swift +++ b/Sources/SwiftOCA/OCC/PropertyTypes/BoundedProperty.swift @@ -191,6 +191,7 @@ public struct OcaBoundedProperty< try await _storage._getValue(object, flags: flags) } + #if NonEmbeddedBuild public func getJsonValue( _ object: OcaRoot, keyPath: AnyKeyPath, @@ -204,6 +205,7 @@ public struct OcaBoundedProperty< "\(jsonKey)": value.value, ] } + #endif @_spi(SwiftOCAPrivate) public func _setValue(_ object: OcaRoot, _ anyValue: Any) async throws { diff --git a/Sources/SwiftOCA/OCC/PropertyTypes/Property.swift b/Sources/SwiftOCA/OCC/PropertyTypes/Property.swift index 244d2bc1..8bac110f 100644 --- a/Sources/SwiftOCA/OCC/PropertyTypes/Property.swift +++ b/Sources/SwiftOCA/OCC/PropertyTypes/Property.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2023 PADL Software Pty Ltd +// Copyright (c) 2023-2026 PADL Software Pty Ltd // // Licensed under the Apache License, Version 2.0 (the License); // you may not use this file except in compliance with the License. @@ -16,7 +16,11 @@ import AsyncAlgorithms import AsyncExtensions +#if NonEmbeddedBuild || !canImport(FoundationEssentials) import Foundation +#else +import FoundationEssentials +#endif public struct OcaPropertyResolutionFlags: OptionSet, Sendable { public typealias RawValue = UInt32 @@ -56,12 +60,14 @@ public protocol OcaPropertyRepresentable: CustomStringConvertible { func refresh(_ object: OcaRoot) async func subscribe(_ object: OcaRoot) async + #if NonEmbeddedBuild func getJsonValue( _ object: OcaRoot, keyPath: AnyKeyPath, flags: OcaPropertyResolutionFlags ) async throws -> [String: any Sendable] + #endif } public extension OcaPropertyRepresentable { @@ -432,6 +438,7 @@ public struct OcaProperty: Codable, Sendable, } } + #if NonEmbeddedBuild public func getJsonValue( _ object: OcaRoot, keyPath: AnyKeyPath, @@ -439,7 +446,12 @@ public struct OcaProperty: Codable, Sendable, ) async throws -> [String: any Sendable] { let value = try await _getValue(object, flags: flags) let jsonValue: any Sendable = if isNil(value) { + #if canImport(Foundation) && !canImport(FoundationEssentials) NSNull() + #else + (any Sendable)?.none + #endif + } else if JSONSerialization.isValidJSONObject(value) { value } else { @@ -448,6 +460,7 @@ public struct OcaProperty: Codable, Sendable, return try [keyPath.jsonKey: jsonValue] } + #endif @_spi(SwiftOCAPrivate) public func _setValue(_ object: OcaRoot, _ anyValue: Any) async throws { @@ -486,6 +499,7 @@ extension OcaProperty.PropertyValue: Hashable where Value: Hashable & Codable { } } +#if NonEmbeddedBuild extension AnyKeyPath { var jsonKey: String { get throws { @@ -510,3 +524,4 @@ extension AnyKeyPath { } } } +#endif diff --git a/Sources/SwiftOCA/OCC/PropertyTypes/VectorProperty.swift b/Sources/SwiftOCA/OCC/PropertyTypes/VectorProperty.swift index d12038a9..eff777e2 100644 --- a/Sources/SwiftOCA/OCC/PropertyTypes/VectorProperty.swift +++ b/Sources/SwiftOCA/OCC/PropertyTypes/VectorProperty.swift @@ -165,6 +165,7 @@ public struct OcaVectorProperty< try await _storage._getValue(object, flags: flags) } + #if NonEmbeddedBuild public func getJsonValue( _ object: OcaRoot, keyPath: AnyKeyPath, @@ -173,6 +174,7 @@ public struct OcaVectorProperty< let value = try await _getValue(object, flags: flags) return try [keyPath.jsonKey: [value.x, value.y]] } + #endif @_spi(SwiftOCAPrivate) public func _setValue(_ object: OcaRoot, _ anyValue: Any) async throws { diff --git a/Sources/SwiftOCA/OCP.1/Backend/Ocp1CFSocketConnection.swift b/Sources/SwiftOCA/OCP.1/Backend/Ocp1CFSocketConnection.swift index 5da99852..60a9e9b7 100644 --- a/Sources/SwiftOCA/OCP.1/Backend/Ocp1CFSocketConnection.swift +++ b/Sources/SwiftOCA/OCP.1/Backend/Ocp1CFSocketConnection.swift @@ -14,7 +14,7 @@ // limitations under the License. // -#if canImport(CoreFoundation) +#if canImport(CoreFoundation) && NonEmbeddedBuild import AsyncAlgorithms import AsyncExtensions diff --git a/Sources/SwiftOCA/OCP.1/Backend/Ocp1FlyingSocksConnection.swift b/Sources/SwiftOCA/OCP.1/Backend/Ocp1FlyingSocksConnection.swift index ab6e5a41..c0c799d7 100644 --- a/Sources/SwiftOCA/OCP.1/Backend/Ocp1FlyingSocksConnection.swift +++ b/Sources/SwiftOCA/OCP.1/Backend/Ocp1FlyingSocksConnection.swift @@ -23,7 +23,7 @@ // SOFTWARE. // -#if os(macOS) || os(iOS) || canImport(Android) +#if os(macOS) || os(iOS) || canImport(Android) || !NonEmbedded import FlyingSocks #if canImport(FoundationEssentials) @@ -35,6 +35,9 @@ import SystemPackage #if canImport(Synchronization) import Synchronization #endif +#if canImport(Glibc) +import Glibc +#endif fileprivate extension SocketError { var mappedError: Error { diff --git a/Sources/SwiftOCA/OCP.1/Ocp1Connection.swift b/Sources/SwiftOCA/OCP.1/Ocp1Connection.swift index 27d952e8..ecb0ea6e 100644 --- a/Sources/SwiftOCA/OCP.1/Ocp1Connection.swift +++ b/Sources/SwiftOCA/OCP.1/Ocp1Connection.swift @@ -39,7 +39,7 @@ public typealias Ocp1TCPConnection = Ocp1IORingStreamConnection #elseif canImport(FlyingSocks) public typealias Ocp1UDPConnection = Ocp1FlyingSocksDatagramConnection public typealias Ocp1TCPConnection = Ocp1FlyingSocksStreamConnection -#else +#elseif canImport(CoreFoundation) && NonEmbedded public typealias Ocp1UDPConnection = Ocp1CFSocketUDPConnection public typealias Ocp1TCPConnection = Ocp1CFSocketTCPConnection #endif diff --git a/Sources/SwiftOCADevice/OCA/DatasetStorageProviders/DatasetStorageProvider.swift b/Sources/SwiftOCADevice/OCA/DatasetStorageProviders/DatasetStorageProvider.swift index 35d1a062..60bb8bb4 100644 --- a/Sources/SwiftOCADevice/OCA/DatasetStorageProviders/DatasetStorageProvider.swift +++ b/Sources/SwiftOCADevice/OCA/DatasetStorageProviders/DatasetStorageProvider.swift @@ -14,6 +14,8 @@ // limitations under the License. // +#if NonEmbeddedBuild + import SwiftOCA public protocol OcaDatasetStorageProvider: Actor { @@ -60,3 +62,5 @@ public protocol OcaDatasetStorageProvider: Actor { func delete(targetONo: OcaONo?, datasetONo: OcaONo) async throws } + +#endif diff --git a/Sources/SwiftOCADevice/OCA/DatasetStorageProviders/FileDatasetStorageProvider.swift b/Sources/SwiftOCADevice/OCA/DatasetStorageProviders/FileDatasetStorageProvider.swift index fd2d71ef..660898db 100644 --- a/Sources/SwiftOCADevice/OCA/DatasetStorageProviders/FileDatasetStorageProvider.swift +++ b/Sources/SwiftOCADevice/OCA/DatasetStorageProviders/FileDatasetStorageProvider.swift @@ -14,6 +14,8 @@ // limitations under the License. // +#if NonEmbeddedBuild + import Foundation import SwiftOCA @@ -207,3 +209,5 @@ public actor OcaFileDatasetStorageProvider: OcaDatasetStorageProvider { try? await deviceDelegate?.deregister(objectNumber: datasetONo) } } + +#endif diff --git a/Sources/SwiftOCADevice/OCA/Device.swift b/Sources/SwiftOCADevice/OCA/Device.swift index e731adea..196441a4 100644 --- a/Sources/SwiftOCADevice/OCA/Device.swift +++ b/Sources/SwiftOCADevice/OCA/Device.swift @@ -50,7 +50,9 @@ public actor OcaDevice { weak var eventDelegate: OcaDeviceEventDelegate? weak var connectionBroker: OcaConnectionBroker? = _OcaDefaultConnectionBroker.shared + #if NonEmbeddedBuild weak var datasetStorageProvider: OcaDatasetStorageProvider? + #endif public func allocateObjectNumber() -> OcaONo { repeat { @@ -279,11 +281,13 @@ public actor OcaDevice { self.connectionBroker = connectionBroker } + #if NonEmbeddedBuild public func setDatasetStorageProvider( _ storageProvider: OcaDatasetStorageProvider ) { datasetStorageProvider = storageProvider } + #endif public func resolve(objectNumber: OcaONo) -> T? { objects[objectNumber] as? T diff --git a/Sources/SwiftOCADevice/OCA/DeviceEndpoint.swift b/Sources/SwiftOCADevice/OCA/DeviceEndpoint.swift index 4c3e41fb..c037d770 100644 --- a/Sources/SwiftOCADevice/OCA/DeviceEndpoint.swift +++ b/Sources/SwiftOCADevice/OCA/DeviceEndpoint.swift @@ -49,6 +49,7 @@ extension OcaDeviceEndpointPrivate { await controller.cancelKeepAlive() Task { await device.eventDelegate?.onControllerExpiry(controller) } + #if NonEmbeddedBuild Task { for dataset in await device.objects.values.compactMap({ $0 as? OcaDataset @@ -56,6 +57,7 @@ extension OcaDeviceEndpointPrivate { await dataset.expireIOSessionHandles(controller: controller) } } + #endif await device.unlockAll(controller: controller) await remove(controller: controller) try? await controller.close() diff --git a/Sources/SwiftOCADevice/OCC/ControlClasses/Dataset/Dataset.swift b/Sources/SwiftOCADevice/OCC/ControlClasses/Dataset/Dataset.swift index 5797ba43..e6653fff 100644 --- a/Sources/SwiftOCADevice/OCC/ControlClasses/Dataset/Dataset.swift +++ b/Sources/SwiftOCADevice/OCC/ControlClasses/Dataset/Dataset.swift @@ -14,6 +14,8 @@ // limitations under the License. // +#if NonEmbeddedBuild + @_spi(SwiftOCAPrivate) import SwiftOCA @@ -312,6 +314,7 @@ extension OcaDataset { } func storeParameters(object: OcaBlock, controller: OcaController?) async throws { + #if NonEmbeddedBuild guard isParamDataset else { throw Ocp1Error.datasetMimeTypeMismatch } @@ -321,6 +324,9 @@ extension OcaDataset { let (_, handle) = try await openWrite(lockState: .noLock, controller: controller) try await write(handle: handle, position: 0, part: blob, controller: controller) try await close(handle: handle, controller: controller) + #else + throw Ocp1Error.notImplemented + #endif } } @@ -373,3 +379,4 @@ extension OcaDataset { try await close(handle: handle, controller: controller) } } +#endif diff --git a/Sources/SwiftOCADevice/OCC/ControlClasses/Dataset/FileDataset.swift b/Sources/SwiftOCADevice/OCC/ControlClasses/Dataset/FileDataset.swift index 820891c8..2ea87d8b 100644 --- a/Sources/SwiftOCADevice/OCC/ControlClasses/Dataset/FileDataset.swift +++ b/Sources/SwiftOCADevice/OCC/ControlClasses/Dataset/FileDataset.swift @@ -14,6 +14,8 @@ // limitations under the License. // +#if NonEmbeddedBuild + import Foundation import SwiftOCA #if canImport(IORing) @@ -367,3 +369,5 @@ final class OcaFileDataset: OcaDataset, OcaCompressibleDataset, @unchecked Senda try (dirEntry.size, maxSize) } } + +#endif diff --git a/Sources/SwiftOCADevice/OCC/ControlClasses/Dataset/Serialization.swift b/Sources/SwiftOCADevice/OCC/ControlClasses/Dataset/Serialization.swift index e43c8199..a1aeee7c 100644 --- a/Sources/SwiftOCADevice/OCC/ControlClasses/Dataset/Serialization.swift +++ b/Sources/SwiftOCADevice/OCC/ControlClasses/Dataset/Serialization.swift @@ -14,6 +14,8 @@ // limitations under the License. // +#if NonEmbeddedBuild + import Foundation #if canImport(Gzip) import Gzip @@ -344,3 +346,5 @@ extension OcaDeviceManager { ) } } + +#endif diff --git a/Sources/SwiftOCADevice/OCC/ControlClasses/Managers/DeviceManager.swift b/Sources/SwiftOCADevice/OCC/ControlClasses/Managers/DeviceManager.swift index ad0d5ec6..413103f3 100644 --- a/Sources/SwiftOCADevice/OCC/ControlClasses/Managers/DeviceManager.swift +++ b/Sources/SwiftOCADevice/OCC/ControlClasses/Managers/DeviceManager.swift @@ -150,6 +150,7 @@ open class OcaDeviceManager: OcaManager { ) public var mostRecentPatchDatasetONo: OcaONo = OcaInvalidONo + #if NonEmbeddedBuild var datasetFilter: OcaRoot.SerializationFilterFunction? = { object, propertyID, _ in precondition(object.objectNumber == OcaDeviceManagerONo) @@ -159,6 +160,7 @@ open class OcaDeviceManager: OcaManager { public func set(datasetFilter: OcaRoot.SerializationFilterFunction?) { self.datasetFilter = datasetFilter } + #endif open func setResetKey( key: Data, @@ -168,6 +170,7 @@ open class OcaDeviceManager: OcaManager { throw Ocp1Error.notImplemented } + #if NonEmbeddedBuild open func applyPatch( datasetONo: OcaONo, controller: OcaController? @@ -182,6 +185,7 @@ open class OcaDeviceManager: OcaManager { try await dataset.applyPatch(to: self, controller: controller) mostRecentPatchDatasetONo = datasetONo } + #endif public convenience init(deviceDelegate: OcaDevice? = nil) async throws { try await self.init( @@ -202,11 +206,13 @@ open class OcaDeviceManager: OcaManager { try await ensureWritable(by: controller, command: command) try await setResetKey(key: Data(parameters.keyBytes), address: parameters.address) return Ocp1Response() + #if NonEmbeddedBuild case OcaMethodID("3.27"): let oNo: OcaONo = try decodeCommand(command) try await ensureWritable(by: controller, command: command) try await applyPatch(datasetONo: oNo, controller: controller) return Ocp1Response() + #endif default: return try await super.handleCommand(command, from: controller) } diff --git a/Sources/SwiftOCADevice/OCC/ControlClasses/Root.swift b/Sources/SwiftOCADevice/OCC/ControlClasses/Root.swift index 8b119f24..dd8e4710 100644 --- a/Sources/SwiftOCADevice/OCC/ControlClasses/Root.swift +++ b/Sources/SwiftOCADevice/OCC/ControlClasses/Root.swift @@ -372,6 +372,7 @@ open class OcaRoot: CustomStringConvertible, Codable, Sendable, _OcaObjectKeyPat } } + #if NonEmbeddedBuild open func serialize( flags: SerializationFlags = [], isIncluded: SerializationFilterFunction? = nil @@ -475,6 +476,7 @@ open class OcaRoot: CustomStringConvertible, Codable, Sendable, _OcaObjectKeyPat public var jsonObject: [String: any Sendable] { try! serialize(flags: .ignoreEncodingErrors) } + #endif } extension OcaRoot: Equatable { diff --git a/Sources/SwiftOCADevice/OCC/ControlClasses/Workers/BlocksAndMatrices/Block.swift b/Sources/SwiftOCADevice/OCC/ControlClasses/Workers/BlocksAndMatrices/Block.swift index d63e191d..9dc24f8b 100644 --- a/Sources/SwiftOCADevice/OCC/ControlClasses/Workers/BlocksAndMatrices/Block.swift +++ b/Sources/SwiftOCADevice/OCC/ControlClasses/Workers/BlocksAndMatrices/Block.swift @@ -23,7 +23,9 @@ public protocol OcaBlockContainer: OcaRoot { associatedtype ActionObject: OcaRoot var actionObjects: [ActionObject] { get } + #if NonEmbeddedBuild var datasetObjects: [OcaDataset] { get async throws } + #endif } open class OcaBlock: OcaWorker, OcaBlockContainer { @@ -36,6 +38,8 @@ open class OcaBlock: OcaWorker, OcaBlockContainer { public var type: OcaONo = OcaInvalidONo public private(set) var actionObjects = [ActionObject]() + + #if NonEmbeddedBuild public var datasetObjects: [OcaDataset] { get async throws { guard let provider = await deviceDelegate?.datasetStorageProvider else { @@ -50,6 +54,7 @@ open class OcaBlock: OcaWorker, OcaBlockContainer { public func set(datasetFilter: OcaRoot.SerializationFilterFunction?) { self.datasetFilter = datasetFilter } + #endif private func notifySubscribers( actionObjects: [ActionObject], @@ -325,6 +330,7 @@ open class OcaBlock: OcaWorker, OcaBlockContainer { }.collect() } + #if NonEmbeddedBuild private typealias DatasetApplyFunction = ( _ member: OcaDataset, _ container: any OcaBlockContainer @@ -590,6 +596,7 @@ open class OcaBlock: OcaWorker, OcaBlockContainer { ) async throws -> [OcaDataset] { throw Ocp1Error.notImplemented } + #endif override open func handleCommand( _ command: Ocp1Command, @@ -669,6 +676,7 @@ open class OcaBlock: OcaWorker, OcaBlockContainer { resultFlags: params.resultFlags ) return try encodeResponse(searchResult) + #if NonEmbeddedBuild case OcaMethodID("3.23"): let params: OcaONo = try decodeCommand(command) try await ensureWritable(by: controller, command: command) @@ -751,7 +759,8 @@ open class OcaBlock: OcaWorker, OcaBlockContainer { return OcaDatasetSearchResult(object: blockMember, name: dataset.name, type: dataset.type) } return try encodeResponse(searchResults) - // 3.32 FindDatasetsRecursive + // 3.32 FindDatasetsRecursive + #endif default: return try await super.handleCommand(command, from: controller) } @@ -762,6 +771,7 @@ open class OcaBlock: OcaWorker, OcaBlockContainer { true } + #if NonEmbeddedBuild override public func serialize( flags: OcaRoot.SerializationFlags = [], isIncluded: OcaRoot.SerializationFilterFunction? = nil @@ -808,6 +818,7 @@ open class OcaBlock: OcaWorker, OcaBlockContainer { try await actionObject.deserialize(jsonObject: actionJsonObject, flags: flags) } } + #endif } public extension OcaRoot { diff --git a/Sources/SwiftOCADevice/OCC/ControlClasses/Workers/BlocksAndMatrices/Matrix.swift b/Sources/SwiftOCADevice/OCC/ControlClasses/Workers/BlocksAndMatrices/Matrix.swift index 99e26593..0b3a9ec4 100644 --- a/Sources/SwiftOCADevice/OCC/ControlClasses/Workers/BlocksAndMatrices/Matrix.swift +++ b/Sources/SwiftOCADevice/OCC/ControlClasses/Workers/BlocksAndMatrices/Matrix.swift @@ -390,6 +390,7 @@ open class OcaMatrix: OcaWorker { true } + #if NonEmbeddedBuild override public func serialize( flags: OcaRoot.SerializationFlags = [], isIncluded: OcaRoot.SerializationFilterFunction? = nil @@ -438,4 +439,5 @@ open class OcaMatrix: OcaWorker { try? await notifySubscribers(members: members, changeType: .itemChanged) } + #endif } diff --git a/Sources/SwiftOCADevice/OCC/PropertyTypes/BoundedDeviceProperty.swift b/Sources/SwiftOCADevice/OCC/PropertyTypes/BoundedDeviceProperty.swift index ec20e7fe..cd3aa7a5 100644 --- a/Sources/SwiftOCADevice/OCC/PropertyTypes/BoundedDeviceProperty.swift +++ b/Sources/SwiftOCADevice/OCC/PropertyTypes/BoundedDeviceProperty.swift @@ -62,6 +62,7 @@ public struct OcaBoundedDeviceProperty< try await storage.getOcp1Response() } + #if NonEmbeddedBuild func getJsonValue() throws -> any Sendable { let valueDict: [String: Value] = ["v": storage.subject.value.value, @@ -70,6 +71,7 @@ public struct OcaBoundedDeviceProperty< return valueDict } + #endif private func setAndNotifySubscribers( object: OcaRoot, @@ -79,6 +81,7 @@ public struct OcaBoundedDeviceProperty< try? await notifySubscribers(object: object, newValue.value) } + #if NonEmbeddedBuild func set(object: OcaRoot, jsonValue: Any, device: OcaDevice) async throws { guard let valueDict = jsonValue as? [String: Value] else { throw Ocp1Error.status(.badFormat) @@ -102,6 +105,7 @@ public struct OcaBoundedDeviceProperty< OcaBoundedPropertyValue(value: value, in: lowerBound...upperBound) ) } + #endif private func _validate(value: Value) throws { // check it is in range diff --git a/Sources/SwiftOCADevice/OCC/PropertyTypes/DeviceProperty.swift b/Sources/SwiftOCADevice/OCC/PropertyTypes/DeviceProperty.swift index ceed07eb..40ee18b9 100644 --- a/Sources/SwiftOCADevice/OCC/PropertyTypes/DeviceProperty.swift +++ b/Sources/SwiftOCADevice/OCC/PropertyTypes/DeviceProperty.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2023 PADL Software Pty Ltd +// Copyright (c) 2023-2026 PADL Software Pty Ltd // // Licensed under the Apache License, Version 2.0 (the License); // you may not use this file except in compliance with the License. @@ -15,7 +15,11 @@ // import AsyncExtensions +#if NonEmbeddedBuild || !canImport(FoundationEssentials) import Foundation +#else +import FoundationEssentials +#endif @_spi(SwiftOCAPrivate) import SwiftOCA @@ -30,13 +34,16 @@ protocol OcaDevicePropertyRepresentable: Sendable { var subject: AsyncCurrentValueSubject { get } func getOcp1Response() async throws -> Ocp1Response - func getJsonValue() throws -> any Sendable /// setters take an object so that subscribers can be notified func set(object: OcaRoot, command: Ocp1Command) async throws - func set(object: OcaRoot, jsonValue: Any, device: OcaDevice) async throws func set(object: OcaRoot, eventData: OcaPropertyChangedEventData) async throws + + #if NonEmbeddedBuild + func getJsonValue() throws -> any Sendable + func set(object: OcaRoot, jsonValue: Any, device: OcaDevice) async throws + #endif } extension OcaDevicePropertyRepresentable { @@ -147,9 +154,14 @@ public struct OcaDeviceProperty: OcaDevicePropertyRep return try OcaRoot.encodeResponse(value) } + #if NonEmbeddedBuild func getJsonValue() throws -> any Sendable { let jsonValue: any Sendable = if isNil(subject.value) { + #if canImport(Foundation) && !canImport(FoundationEssentials) NSNull() + #else + (any Sendable)?.none + #endif } else if JSONSerialization.isValidJSONObject(subject.value) { subject.value } else { @@ -158,6 +170,7 @@ public struct OcaDeviceProperty: OcaDevicePropertyRep return jsonValue } + #endif func set(object: OcaRoot, command: Ocp1Command) async throws { let newValue: Value = try OcaRoot.decodeCommand(command) @@ -173,6 +186,7 @@ public struct OcaDeviceProperty: OcaDevicePropertyRep } } + #if NonEmbeddedBuild func set(object: OcaRoot, jsonValue: Any, device: OcaDevice) async throws { if jsonValue is NSNull { if let subject = subject as? AsyncCurrentValueSubjectNilRepresentable { @@ -216,6 +230,7 @@ public struct OcaDeviceProperty: OcaDevicePropertyRep } } } + #endif private func notifySubscribers(object: OcaRoot, _ newValue: Value) async throws { let event = OcaEvent(emitterONo: object.objectNumber, eventID: OcaPropertyChangedEventID) diff --git a/Sources/SwiftOCADevice/OCC/PropertyTypes/VectorDeviceProperty.swift b/Sources/SwiftOCADevice/OCC/PropertyTypes/VectorDeviceProperty.swift index bb46949a..fa1f89dc 100644 --- a/Sources/SwiftOCADevice/OCC/PropertyTypes/VectorDeviceProperty.swift +++ b/Sources/SwiftOCADevice/OCC/PropertyTypes/VectorDeviceProperty.swift @@ -68,6 +68,7 @@ public struct OcaVectorDeviceProperty< try await storage.getOcp1Response() } + #if NonEmbeddedBuild func getJsonValue() throws -> any Sendable { let valueDict: [String: Value] = ["x": storage.subject.value.x, @@ -75,12 +76,14 @@ public struct OcaVectorDeviceProperty< return valueDict } + #endif private func setAndNotifySubscribers(object: OcaRoot, _ newValue: OcaVector2D) async { storage.subject.send(newValue) try? await notifySubscribers(object: object, newValue) } + #if NonEmbeddedBuild func set(object: OcaRoot, jsonValue: Any, device: OcaDevice) async throws { guard let valueDict = jsonValue as? [String: Value] else { throw Ocp1Error.status(.badFormat) @@ -94,6 +97,7 @@ public struct OcaVectorDeviceProperty< await setAndNotifySubscribers(object: object, OcaVector2D(x: x, y: y)) } + #endif func set(object: OcaRoot, command: Ocp1Command) async throws { let newValue: OcaVector2D = try object.decodeCommand(command) diff --git a/Sources/SwiftOCADevice/OCP.1/Backend/CF/Ocp1CFController.swift b/Sources/SwiftOCADevice/OCP.1/Backend/CF/Ocp1CFController.swift index ccc42ff9..eab2d4af 100644 --- a/Sources/SwiftOCADevice/OCP.1/Backend/CF/Ocp1CFController.swift +++ b/Sources/SwiftOCADevice/OCP.1/Backend/CF/Ocp1CFController.swift @@ -14,7 +14,7 @@ // limitations under the License. // -#if canImport(CoreFoundation) +#if canImport(CoreFoundation) && NonEmbeddedBuild import AsyncAlgorithms import AsyncExtensions diff --git a/Sources/SwiftOCADevice/OCP.1/Backend/CF/Ocp1CFDeviceEndpoint.swift b/Sources/SwiftOCADevice/OCP.1/Backend/CF/Ocp1CFDeviceEndpoint.swift index af01b00e..25552457 100644 --- a/Sources/SwiftOCADevice/OCP.1/Backend/CF/Ocp1CFDeviceEndpoint.swift +++ b/Sources/SwiftOCADevice/OCP.1/Backend/CF/Ocp1CFDeviceEndpoint.swift @@ -14,7 +14,7 @@ // limitations under the License. // -#if canImport(CoreFoundation) +#if canImport(CoreFoundation) && NonEmbeddedBuild import AsyncAlgorithms import AsyncExtensions diff --git a/Sources/SwiftOCADevice/OCP.1/Backend/FlyingSocks/Ocp1FlyingFoxController.swift b/Sources/SwiftOCADevice/OCP.1/Backend/FlyingSocks/Ocp1FlyingFoxController.swift index 16305bb7..4d102c0a 100644 --- a/Sources/SwiftOCADevice/OCP.1/Backend/FlyingSocks/Ocp1FlyingFoxController.swift +++ b/Sources/SwiftOCADevice/OCP.1/Backend/FlyingSocks/Ocp1FlyingFoxController.swift @@ -14,7 +14,7 @@ // limitations under the License. // -#if os(macOS) || os(iOS) +#if canImport(FlyingFox) import AsyncExtensions import FlyingFox diff --git a/Sources/SwiftOCADevice/OCP.1/Backend/FlyingSocks/Ocp1FlyingFoxDeviceEndpoint.swift b/Sources/SwiftOCADevice/OCP.1/Backend/FlyingSocks/Ocp1FlyingFoxDeviceEndpoint.swift index 2285be6c..1a50c2d1 100644 --- a/Sources/SwiftOCADevice/OCP.1/Backend/FlyingSocks/Ocp1FlyingFoxDeviceEndpoint.swift +++ b/Sources/SwiftOCADevice/OCP.1/Backend/FlyingSocks/Ocp1FlyingFoxDeviceEndpoint.swift @@ -14,7 +14,7 @@ // limitations under the License. // -#if os(macOS) || os(iOS) +#if canImport(FlyingFox) import AsyncExtensions import FlyingFox @@ -26,6 +26,9 @@ import Foundation #endif import Logging import SwiftOCA +#if canImport(Glibc) +import Glibc +#endif @OcaDevice public final class Ocp1FlyingFoxDeviceEndpoint: OcaDeviceEndpointPrivate, diff --git a/Sources/SwiftOCADevice/OCP.1/Backend/FlyingSocks/Ocp1FlyingSocksDatagramController.swift b/Sources/SwiftOCADevice/OCP.1/Backend/FlyingSocks/Ocp1FlyingSocksDatagramController.swift index c7ef7687..f87e2bdb 100644 --- a/Sources/SwiftOCADevice/OCP.1/Backend/FlyingSocks/Ocp1FlyingSocksDatagramController.swift +++ b/Sources/SwiftOCADevice/OCP.1/Backend/FlyingSocks/Ocp1FlyingSocksDatagramController.swift @@ -14,7 +14,7 @@ // limitations under the License. // -#if os(macOS) || os(iOS) +#if os(macOS) || os(iOS) || !NonEmbedded import AsyncAlgorithms import AsyncExtensions @@ -26,6 +26,9 @@ import Foundation #endif @_spi(SwiftOCAPrivate) import SwiftOCA +#if canImport(Glibc) +import Glibc +#endif /// A remote controller actor Ocp1FlyingSocksDatagramController: Ocp1ControllerInternal { diff --git a/Sources/SwiftOCADevice/OCP.1/Backend/FlyingSocks/Ocp1FlyingSocksDatagramDeviceEndpoint.swift b/Sources/SwiftOCADevice/OCP.1/Backend/FlyingSocks/Ocp1FlyingSocksDatagramDeviceEndpoint.swift index 6d5b6180..bffbd1f6 100644 --- a/Sources/SwiftOCADevice/OCP.1/Backend/FlyingSocks/Ocp1FlyingSocksDatagramDeviceEndpoint.swift +++ b/Sources/SwiftOCADevice/OCP.1/Backend/FlyingSocks/Ocp1FlyingSocksDatagramDeviceEndpoint.swift @@ -23,7 +23,7 @@ // SOFTWARE. // -#if os(macOS) || os(iOS) +#if os(macOS) || os(iOS) || !NonEmbedded import AsyncExtensions import FlyingSocks diff --git a/Sources/SwiftOCADevice/OCP.1/Backend/FlyingSocks/Ocp1FlyingSocksLogging.swift b/Sources/SwiftOCADevice/OCP.1/Backend/FlyingSocks/Ocp1FlyingSocksLogging.swift index d760bfc0..da7d81c1 100644 --- a/Sources/SwiftOCADevice/OCP.1/Backend/FlyingSocks/Ocp1FlyingSocksLogging.swift +++ b/Sources/SwiftOCADevice/OCP.1/Backend/FlyingSocks/Ocp1FlyingSocksLogging.swift @@ -23,7 +23,7 @@ // SOFTWARE. // -#if os(macOS) || os(iOS) +#if os(macOS) || os(iOS) || !NonEmbedded import FlyingSocks diff --git a/Sources/SwiftOCADevice/OCP.1/Backend/FlyingSocks/Ocp1FlyingSocksStreamController.swift b/Sources/SwiftOCADevice/OCP.1/Backend/FlyingSocks/Ocp1FlyingSocksStreamController.swift index fde4bb7a..9a284373 100644 --- a/Sources/SwiftOCADevice/OCP.1/Backend/FlyingSocks/Ocp1FlyingSocksStreamController.swift +++ b/Sources/SwiftOCADevice/OCP.1/Backend/FlyingSocks/Ocp1FlyingSocksStreamController.swift @@ -14,7 +14,7 @@ // limitations under the License. // -#if os(macOS) || os(iOS) +#if os(macOS) || os(iOS) || !NonEmbedded import AsyncAlgorithms import AsyncExtensions @@ -26,6 +26,9 @@ import Foundation #endif @_spi(SwiftOCAPrivate) import SwiftOCA +#if canImport(Glibc) +import Glibc +#endif /// A remote controller actor Ocp1FlyingSocksStreamController: Ocp1ControllerInternal, CustomStringConvertible { @@ -155,7 +158,7 @@ private extension AsyncThrowingStream AsyncThrowingStream { do { return try await withThrowingTimeout(of: timeout, clock: .continuous) { - var iterator = bytes.makeAsyncIterator() + nonisolated(unsafe) var iterator = bytes.makeAsyncIterator() return try await OcaDevice.asyncReceiveMessages { count in var nremain = count var buffer = [UInt8]() @@ -185,7 +188,7 @@ private extension AsyncThrowingStream } extension OcaDevice { - static func asyncReceiveMessages(_ read: (Int) async throws -> [UInt8]) async throws + static func asyncReceiveMessages(_ read: @Sendable (Int) async throws -> [UInt8]) async throws -> Ocp1MessageList { try await receiveMessages(read) diff --git a/Sources/SwiftOCADevice/OCP.1/Backend/FlyingSocks/Ocp1FlyingSocksStreamDeviceEndpoint.swift b/Sources/SwiftOCADevice/OCP.1/Backend/FlyingSocks/Ocp1FlyingSocksStreamDeviceEndpoint.swift index 76152804..809b9cae 100644 --- a/Sources/SwiftOCADevice/OCP.1/Backend/FlyingSocks/Ocp1FlyingSocksStreamDeviceEndpoint.swift +++ b/Sources/SwiftOCADevice/OCP.1/Backend/FlyingSocks/Ocp1FlyingSocksStreamDeviceEndpoint.swift @@ -23,7 +23,7 @@ // SOFTWARE. // -#if os(macOS) || os(iOS) +#if os(macOS) || os(iOS) || !NonEmbedded import AsyncExtensions import FlyingSocks diff --git a/Sources/SwiftOCADevice/OCP.1/Ocp1Controller.swift b/Sources/SwiftOCADevice/OCP.1/Ocp1Controller.swift index 833e0d7a..10b981ed 100644 --- a/Sources/SwiftOCADevice/OCP.1/Ocp1Controller.swift +++ b/Sources/SwiftOCADevice/OCP.1/Ocp1Controller.swift @@ -16,10 +16,13 @@ import SwiftOCA -#if os(macOS) || os(iOS) +// macOS, iOS, embedded Linux uses FlyingSocks because it does not pull in +// Foundation and because not all embedded Linux distributions have recent +// enough kernels to support io_uring + +#if os(macOS) || os(iOS) || !NonEmbeddedBuild typealias Ocp1Controller = Ocp1FlyingSocksStreamController public typealias Ocp1DeviceEndpoint = Ocp1FlyingSocksStreamDeviceEndpoint -public typealias Ocp1WSDeviceEndpoint = Ocp1FlyingFoxDeviceEndpoint #elseif os(Linux) typealias Ocp1Controller = Ocp1IORingStreamController public typealias Ocp1DeviceEndpoint = Ocp1IORingStreamDeviceEndpoint @@ -27,3 +30,7 @@ public typealias Ocp1DeviceEndpoint = Ocp1IORingStreamDeviceEndpoint typealias Ocp1Controller = Ocp1CFStreamController public typealias Ocp1DeviceEndpoint = Ocp1CFStreamDeviceEndpoint #endif + +#if NonEmbeddedBuild +public typealias Ocp1WSDeviceEndpoint = Ocp1FlyingFoxDeviceEndpoint +#endif