From 9e389d104076c7060dc87b49ce16fb586f42e2f8 Mon Sep 17 00:00:00 2001 From: Alsey Coleman Miller Date: Mon, 18 Nov 2024 18:55:05 +0000 Subject: [PATCH] Add `LosslessStringConvertible` conformance to `BluetoothUUID` --- Sources/Bluetooth/BluetoothUUID.swift | 60 +++++++++++++++---- Tests/BluetoothTests/BluetoothUUIDTests.swift | 19 ++++++ 2 files changed, 67 insertions(+), 12 deletions(-) diff --git a/Sources/Bluetooth/BluetoothUUID.swift b/Sources/Bluetooth/BluetoothUUID.swift index e986a482c..dadae30f7 100644 --- a/Sources/Bluetooth/BluetoothUUID.swift +++ b/Sources/Bluetooth/BluetoothUUID.swift @@ -27,6 +27,24 @@ public extension BluetoothUUID { } } +// MARK: - Equatable + +extension BluetoothUUID: Equatable { + + public static func == (lhs: BluetoothUUID, rhs: BluetoothUUID) -> Bool { + switch (lhs, rhs) { + case let (.bit16(lhsValue), .bit16(rhsValue)): + return lhsValue == rhsValue + case let (.bit32(lhsValue), .bit32(rhsValue)): + return lhsValue == rhsValue + case let (.bit128(lhsValue), .bit128(rhsValue)): + return lhsValue == rhsValue + default: + return false + } + } +} + // MARK: - CustomStringConvertible extension BluetoothUUID: CustomStringConvertible { @@ -44,21 +62,39 @@ extension BluetoothUUID: CustomStringConvertible { } } -// MARK: - Equatable +// MARK: - LosslessStringConvertible -extension BluetoothUUID: Equatable { +extension BluetoothUUID: LosslessStringConvertible { - public static func == (lhs: BluetoothUUID, rhs: BluetoothUUID) -> Bool { - switch (lhs, rhs) { - case let (.bit16(lhsValue), .bit16(rhsValue)): - return lhsValue == rhsValue - case let (.bit32(lhsValue), .bit32(rhsValue)): - return lhsValue == rhsValue - case let (.bit128(lhsValue), .bit128(rhsValue)): - return lhsValue == rhsValue - default: - return false + public init?(_ string: String) { + #if !os(WASI) && !hasFeature(Embedded) + var rawValue = string + var name: String? + // Find UUID name + let components = string.split( + maxSplits: 1, + omittingEmptySubsequences: true, + whereSeparator: { $0 == " " } + ) + if components.count == 2 { + rawValue = String(components[0]) + name = String(components[1]) + // remove parenthesis + if name?.first == "(", name?.last == ")" { + name?.removeFirst() + name?.removeLast() + } + } + self.init(rawValue: rawValue) + // validate name + if let name { + guard name == self.name else { + return nil + } } + #else + self.init(rawValue: string) + #endif } } diff --git a/Tests/BluetoothTests/BluetoothUUIDTests.swift b/Tests/BluetoothTests/BluetoothUUIDTests.swift index a97ba4a89..54881ca3b 100644 --- a/Tests/BluetoothTests/BluetoothUUIDTests.swift +++ b/Tests/BluetoothTests/BluetoothUUIDTests.swift @@ -226,6 +226,25 @@ final class BluetoothUUIDTests: XCTestCase { } } + func testLosslessStringConvertible() { + + let data: [(BluetoothUUID, String)] = [ + (.bit16(0x1800), "1800"), + (.bit16(0x1800), "1800 (Generic Access Profile)"), + (.bit16(0xFEA9), "FEA9"), + (.bit16(0xFEA9), "FEA9 (Savant Systems LLC)"), + (.bit32(0x12345678).bit128, "12345678-0000-1000-8000-00805F9B34FB") + ] + + for (uuid, string) in data { + guard let parsed = BluetoothUUID(string) else { + XCTFail("Unable to parse: \(string)") + continue + } + XCTAssertEqual(parsed, uuid) + } + } + func testPerformanceStringParse() { let uuids = randomUUIDs.map { $0.uuidString }