From 80ba6bf89eb6bf6b32d0b82168c38d2ce268d4c5 Mon Sep 17 00:00:00 2001 From: Alsey Coleman Miller Date: Mon, 4 Nov 2024 19:32:30 -0500 Subject: [PATCH] #161 Use `DataContainer` with `GAPData` --- .../BluetoothGAP/GAPCompleteLocalName.swift | 17 ++--- Sources/BluetoothGAP/GAPData.swift | 38 +--------- Sources/BluetoothGAP/GAPFlags.swift | 17 ++--- Sources/BluetoothGAP/iBeacon.swift | 69 ++++++++----------- 4 files changed, 40 insertions(+), 101 deletions(-) diff --git a/Sources/BluetoothGAP/GAPCompleteLocalName.swift b/Sources/BluetoothGAP/GAPCompleteLocalName.swift index 3b597d488..348e577c9 100644 --- a/Sources/BluetoothGAP/GAPCompleteLocalName.swift +++ b/Sources/BluetoothGAP/GAPCompleteLocalName.swift @@ -6,8 +6,6 @@ // Copyright © 2018 PureSwift. All rights reserved. // -import Foundation - /** GAP Complete Local Name @@ -16,33 +14,30 @@ import Foundation @frozen public struct GAPCompleteLocalName: GAPData, Equatable, Hashable { - public static let dataType: GAPDataType = .completeLocalName + public static var dataType: GAPDataType { .completeLocalName } - public let name: String + public var name: String public init(name: String) { - self.name = name } } public extension GAPCompleteLocalName { - init?(data: Data) { + init?(data: Data) { - guard let rawValue = String(data: data, encoding: .utf8) + guard let rawValue = String(utf8: data) else { return nil } self.init(name: rawValue) } - func append(to data: inout Data) { - + func append(to data: inout Data) { data += name.utf8 } var dataLength: Int { - return name.utf8.count } } @@ -52,7 +47,6 @@ public extension GAPCompleteLocalName { extension GAPCompleteLocalName: CustomStringConvertible { public var description: String { - return name } } @@ -62,7 +56,6 @@ extension GAPCompleteLocalName: CustomStringConvertible { extension GAPCompleteLocalName: ExpressibleByStringLiteral { public init(stringLiteral value: String) { - self.init(name: value) } } diff --git a/Sources/BluetoothGAP/GAPData.swift b/Sources/BluetoothGAP/GAPData.swift index 17855e6c3..5ac1d3678 100644 --- a/Sources/BluetoothGAP/GAPData.swift +++ b/Sources/BluetoothGAP/GAPData.swift @@ -6,7 +6,6 @@ // Copyright © 2018 PureSwift. All rights reserved. // -import Foundation @_exported import Bluetooth // MARK: - Generic Access Profile Data @@ -22,43 +21,12 @@ public protocol GAPData { /// Generic Access Profile data type. static var dataType: GAPDataType { get } - /// Initialize from LE advertisement data. - init?(data: Slice) - - /// Initialize from bytes. - init?(data: Data) - - /// Append data representation into buffer. - func append(to data: inout Data) + /// Initialize from data. + init?(data: Data) /// Append data representation into buffer. - func append(to data: inout LowEnergyAdvertisingData) + func append(to data: inout Data) /// Length of value when encoded into data. var dataLength: Int { get } } - -public extension GAPData { - - init?(data slice: Slice) { - let range = slice.startIndex ..< slice.endIndex - guard let value = slice.base.withUnsafeData({ - Self.init(data: $0.subdataNoCopy(in: range)) - }) else { return nil } - self = value - } - - func append(to data: inout LowEnergyAdvertisingData) { - data += Data(self) // will be serialized on stack if small - } -} - -public extension Data { - - /// Initialize from GAP Data type. - init(_ value: T) { - self.init(capacity: value.dataLength) - value.append(to: &self) - assert(self.count == value.dataLength) - } -} diff --git a/Sources/BluetoothGAP/GAPFlags.swift b/Sources/BluetoothGAP/GAPFlags.swift index c501964e2..421f1d71f 100644 --- a/Sources/BluetoothGAP/GAPFlags.swift +++ b/Sources/BluetoothGAP/GAPFlags.swift @@ -6,14 +6,13 @@ // Copyright © 2018 PureSwift. All rights reserved. // -import Foundation import Bluetooth /// GAP Flag @frozen public struct GAPFlags: GAPData, Equatable, Hashable { - public static var dataType: GAPDataType { return .flags } + public static var dataType: GAPDataType { .flags } public var flags: BitMaskOptionSet @@ -24,24 +23,20 @@ public struct GAPFlags: GAPData, Equatable, Hashable { public extension GAPFlags { - init?(data: Data) { - + init?(data: Data) where Data : Bluetooth.DataContainer { + guard data.count == 1 else { return nil } self.flags = BitMaskOptionSet(rawValue: data[0]) } - func append(to data: inout Data) { - data += self - } - - func append(to data: inout LowEnergyAdvertisingData) { + func append(to data: inout Data) where Data : Bluetooth.DataContainer { data += self } var dataLength: Int { - return 1 + 1 } } @@ -59,7 +54,6 @@ extension GAPFlags: DataConvertible { extension GAPFlags: CustomStringConvertible { public var description: String { - return flags.description } } @@ -69,7 +63,6 @@ extension GAPFlags: CustomStringConvertible { extension GAPFlags: ExpressibleByIntegerLiteral { public init(integerLiteral rawValue: GAPFlag.RawValue) { - self.init(flags: BitMaskOptionSet(rawValue: rawValue)) } } diff --git a/Sources/BluetoothGAP/iBeacon.swift b/Sources/BluetoothGAP/iBeacon.swift index 1a54d94f6..8f1e74bcb 100644 --- a/Sources/BluetoothGAP/iBeacon.swift +++ b/Sources/BluetoothGAP/iBeacon.swift @@ -5,12 +5,14 @@ // Created by Alsey Coleman Miller on 10/22/20. // +#if canImport(Foundation) import Foundation +#endif import Bluetooth public extension AppleBeacon { - init?(manufacturerData: GAPManufacturerSpecificData) { + init?(manufacturerData: GAPManufacturerSpecificData) { let data = manufacturerData.additionalData @@ -28,46 +30,46 @@ public extension AppleBeacon { guard length == type(of: self).length else { return nil } - let uuid = UUID(UInt128(bigEndian: UInt128(data: data.subdataNoCopy(in: 2 ..< 18))!)) + let uuid = UUID(UInt128(bigEndian: UInt128(data: data.subdata(in: 2 ..< 18))!)) let major = UInt16(bigEndian: UInt16(bytes: (data[18], data[19]))) let minor = UInt16(bigEndian: UInt16(bytes: (data[20], data[21]))) let rssi = Int8(bitPattern: data[22]) self.init(uuid: uuid, major: major, minor: minor, rssi: rssi) } +} + +public extension GAPManufacturerSpecificData { - var manufacturerData: GAPManufacturerSpecificData { - - var additionalData = Data(capacity: type(of: self).additionalDataLength) - appendAdditionalManufacturerData(to: &additionalData) - assert(additionalData.count == type(of: self).additionalDataLength) - - let manufacturerData = GAPManufacturerSpecificData( - companyIdentifier: type(of: self).companyIdentifier, + init(beacon: AppleBeacon) { + var additionalData = AdditionalData() + additionalData.reserveCapacity(AppleBeacon.additionalDataLength) + beacon.appendAdditionalManufacturerData(to: &additionalData) + assert(additionalData.count == AppleBeacon.additionalDataLength) + self.init( + companyIdentifier: AppleBeacon.companyIdentifier, additionalData: additionalData ) - - return manufacturerData } } internal extension AppleBeacon { /// Apple iBeacon data type. - static var appleDataType: UInt8 { return 0x02 } // iBeacon + static var appleDataType: UInt8 { 0x02 } // iBeacon /// The length of the TLV encoded data. - static var length: UInt8 { return 0x15 } // length: 21 = 16 byte UUID + 2 bytes major + 2 bytes minor + 1 byte RSSI + static var length: UInt8 { 0x15 } // length: 21 = 16 byte UUID + 2 bytes major + 2 bytes minor + 1 byte RSSI static var additionalDataLength: Int { return Int(length) + 2 } - + /* static func from(advertisingData: LowEnergyAdvertisingData) -> (beacon: AppleBeacon, flags: GAPFlags)? { guard let (flags, manufacturerData) = try? GAPDataDecoder.decode(GAPFlags.self, AppleBeacon.ManufacturerData.self, from: advertisingData) else { return nil } return (manufacturerData.beacon, flags) - } + }*/ func appendAdditionalManufacturerData (to data: inout T) { @@ -85,10 +87,9 @@ public extension LowEnergyAdvertisingData { init(beacon: AppleBeacon, flags: GAPFlags = [.lowEnergyGeneralDiscoverableMode, .notSupportedBREDR]) { - let encoder = GAPDataEncoder() + let encoder = GAPDataEncoder() let manufacturerData = AppleBeacon.ManufacturerData(beacon) // storage on stack - do { self = try encoder.encodeAdvertisingData(flags, manufacturerData) } - catch { fatalError("Unable to encode iBeacon advertisement: \(error)") } + self = encoder.encode(flags, manufacturerData) } } @@ -96,7 +97,7 @@ internal extension AppleBeacon { struct ManufacturerData: GAPData { - static var dataType: GAPDataType { return .manufacturerSpecificData } + static var dataType: GAPDataType { .manufacturerSpecificData } internal let beacon: AppleBeacon @@ -104,18 +105,9 @@ internal extension AppleBeacon { self.beacon = beacon } - init?(data: Data) { - - guard let manufacturerData = GAPManufacturerSpecificData(data: data), - let beacon = AppleBeacon(manufacturerData: manufacturerData) - else { return nil } - - self.init(beacon) - } - - init?(data slice: Slice) { - - guard let manufacturerData = GAPManufacturerSpecificData(data: slice), + init?(data: Data) where Data : DataContainer { + + guard let manufacturerData = GAPManufacturerSpecificData(data: data), let beacon = AppleBeacon(manufacturerData: manufacturerData) else { return nil } @@ -124,13 +116,7 @@ internal extension AppleBeacon { var dataLength: Int { return 2 + AppleBeacon.additionalDataLength } - /// Append data representation into buffer. - func append(to data: inout Data) { - data += self - } - - /// Append data representation into buffer. - func append(to data: inout LowEnergyAdvertisingData) { + func append(to data: inout Data) where Data : DataContainer { data += self } } @@ -139,9 +125,8 @@ internal extension AppleBeacon { extension AppleBeacon.ManufacturerData: DataConvertible { @usableFromInline - static func += (data: inout T, value: AppleBeacon.ManufacturerData) where T : DataContainer { - - data += GAPManufacturerSpecificData(companyIdentifier: AppleBeacon.companyIdentifier) + static func += (data: inout Data, value: AppleBeacon.ManufacturerData) where Data : DataContainer { + data += GAPManufacturerSpecificData(companyIdentifier: AppleBeacon.companyIdentifier) value.beacon.appendAdditionalManufacturerData(to: &data) } }