Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use standard library UInt128 #164

Merged
merged 12 commits into from
Nov 4, 2024
10 changes: 2 additions & 8 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# [Choice] Swift version: 5.6-focal, 5.5, 5.4, 5.3, 5.2, 5.1, 4.2
ARG VARIANT=5.7.1-jammy
# [Choice] Swift version:
ARG VARIANT=6.0.2-jammy
FROM swift:${VARIANT}

# [Option] Install zsh
@@ -25,9 +25,3 @@ COPY library-scripts/node-debian.sh /tmp/library-scripts/
RUN bash /tmp/library-scripts/node-debian.sh "${NVM_DIR}" "${NODE_VERSION}" "${USERNAME}" \
&& rm -rf /var/lib/apt/lists/* /tmp/library-scripts

# [Optional] Uncomment this section to install additional OS packages you may want.
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# && apt-get -y install --no-install-recommends <your-package-list-here>

# [Optional] Uncomment this line to install global node packages.
# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@
"dockerfile": "Dockerfile",
"args": {
// Update the VARIANT arg to pick a Swift version
"VARIANT": "5.7.1-jammy",
"VARIANT": "6.0.2-jammy",
// Options
"NODE_VERSION": "lts/*",
"UPGRADE_PACKAGES": "true"
14 changes: 0 additions & 14 deletions .github/workflows/swift-wasm.yml

This file was deleted.

4 changes: 2 additions & 2 deletions .github/workflows/swift.yml
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ jobs:
- name: Install Swift
uses: slashmo/[email protected]
with:
version: 6.0
version: 6.0.2
- name: Checkout
uses: actions/checkout@v2
- name: Swift Version
@@ -25,7 +25,7 @@ jobs:
name: Linux
strategy:
matrix:
swift: [5.9, 6.0]
swift: [6.0.2]
runs-on: ubuntu-20.04
steps:
- name: Install Swift
53 changes: 22 additions & 31 deletions Sources/Bluetooth/BluetoothUUID.swift
Original file line number Diff line number Diff line change
@@ -19,6 +19,14 @@ public enum BluetoothUUID: Equatable, Hashable, Sendable {
case bit128(UInt128)
}

public extension BluetoothUUID {

/// Creates a random 128-bit Bluetooth UUID.
init() {
self.init(uuid: UUID())
}
}

// MARK: - CustomStringConvertible

extension BluetoothUUID: CustomStringConvertible {
@@ -31,25 +39,13 @@ extension BluetoothUUID: CustomStringConvertible {
return rawValue
}
#else
return _description
return rawValue
#endif
}

internal var _description: String {
switch self {
case let .bit16(value):
return value.toHexadecimal()
case let .bit32(value):
return value.toHexadecimal()
case let .bit128(value):
return value.uuidString
}
}
}

// MARK: - RawRepresentable

#if !hasFeature(Embedded)
extension BluetoothUUID: RawRepresentable {

/// Initialize from a UUID string (in big endian representation).
@@ -61,19 +57,18 @@ extension BluetoothUUID: RawRepresentable {

case 4:

guard let value = UInt16(rawValue, radix: 16)
guard let value = UInt16(hexadecimal: rawValue)
else { return nil }
self = .bit16(value)

case 8:

guard let value = UInt32(rawValue, radix: 16)
guard let value = UInt32(hexadecimal: rawValue)
else { return nil }
self = .bit32(value)

case 36:

// UUID string is always big endian
guard let uuid = UInt128(uuidString: rawValue)
else { return nil }
self = .bit128(uuid)
@@ -84,23 +79,21 @@ extension BluetoothUUID: RawRepresentable {
}

public var rawValue: String {
_description
switch self {
case let .bit16(value):
return value.toHexadecimal()
case let .bit32(value):
return value.toHexadecimal()
case let .bit128(value):
return value.uuidString
}
}
}
#endif

// MARK: - Data

#if canImport(Foundation)

public extension BluetoothUUID {

/// Creates a random 128 bit Bluetooth UUID.
init() {
self.init(uuid: UUID())
}
}

public extension BluetoothUUID {

init?(data: Data) {
@@ -212,7 +205,6 @@ public extension BluetoothUUID {
}
}

#if canImport(Foundation)
internal extension UUID {

@inline(__always)
@@ -242,7 +234,7 @@ internal extension UUID {
public extension UInt16 {

/// Attempt to extract Bluetooth 16-bit UUID from standard 128-bit UUID.
init?(bluetooth uuid: Foundation.UUID) {
init?(bluetooth uuid: UUID) {

guard let prefixBytes = uuid.bluetoothPrefix(),
prefixBytes.0 == 0,
@@ -256,7 +248,7 @@ public extension UInt16 {
public extension UInt32 {

/// Attempt to extract Bluetooth 32-bit UUID from standard 128-bit UUID.
init?(bluetooth uuid: Foundation.UUID) {
init?(bluetooth uuid: UUID) {

guard let prefixBytes = uuid.bluetoothPrefix()
else { return nil }
@@ -275,7 +267,7 @@ public extension BluetoothUUID {
}
}

public extension Foundation.UUID {
public extension UUID {

/// Initialize and convert from a Bluetooth UUID.
init(bluetooth uuid: BluetoothUUID) {
@@ -308,4 +300,3 @@ public extension CBUUID {
}

#endif
#endif
99 changes: 74 additions & 25 deletions Sources/Bluetooth/Extensions/Hexadecimal.swift
Original file line number Diff line number Diff line change
@@ -30,37 +30,86 @@ internal extension Collection where Element: FixedWidthInteger {
}
}

#if !hasFeature(Embedded)
internal extension StringProtocol {
internal extension UInt {

var hexadecimal: UnfoldSequence<UInt8, Index> {
sequence(state: startIndex) { startIndex in
guard startIndex < self.endIndex else { return nil }
let endIndex = self.index(startIndex, offsetBy: 2, limitedBy: self.endIndex) ?? self.endIndex
defer { startIndex = endIndex }
return UInt8(self[startIndex..<endIndex], radix: 16)
init?(parse string: String, radix: UInt) {
let digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
var result = UInt(0)
for digit in string {
#if hasFeature(Embedded)
let character = digit
#else
let character = String(digit).uppercased().first!
#endif
if let stringIndex = digits.enumerated().first(where: { $0.element == character })?.offset {
let val = UInt(stringIndex)
if val >= radix {
return nil
}
result = result * radix + val
} else {
return nil
}
}
self = result
}
}

internal extension UInt16 {

init?(hexadecimal string: String) {
guard string.count == MemoryLayout<Self>.size * 2 else {
return nil
}
#if hasFeature(Embedded) || DEBUG
guard let value = UInt(parse: string, radix: 16) else {
return nil
}
self.init(value)
#else
self.init(string, radix: 16)
#endif
}
}

internal extension UInt32 {

init?(hexadecimal string: String) {
guard string.count == MemoryLayout<Self>.size * 2 else {
return nil
}
#if hasFeature(Embedded) || DEBUG
guard let value = UInt(parse: string, radix: 16) else {
return nil
}
self.init(value)
#else
self.init(string, radix: 16)
#endif
}
}

internal extension String.UTF16View.Element {

// Convert 0 ... 9, a ... f, A ...F to their decimal value,
// return nil for all other input characters
func decodeHexNibble() -> UInt8? {
switch self {
case 0x30 ... 0x39:
return UInt8(self - 0x30)
case 0x41 ... 0x46:
return UInt8(self - 0x41 + 10)
case 0x61 ... 0x66:
return UInt8(self - 0x61 + 10)
default:
return nil
}
}
}
#endif

internal extension [UInt8] {

init?<S: StringProtocol>(hexadecimal string: S) {
// Convert 0 ... 9, a ... f, A ...F to their decimal value,
// return nil for all other input characters
func decodeNibble(_ u: UInt16) -> UInt8? {
switch(u) {
case 0x30 ... 0x39:
return UInt8(u - 0x30)
case 0x41 ... 0x46:
return UInt8(u - 0x41 + 10)
case 0x61 ... 0x66:
return UInt8(u - 0x61 + 10)
default:
return nil
}
}

let str = String(string)
let utf16: String.UTF16View
@@ -74,9 +123,9 @@ internal extension [UInt8] {

var i = utf16.startIndex
while i != utf16.endIndex {
guard let hi = decodeNibble(utf16[i]),
guard let hi = utf16[i].decodeHexNibble(),
let nxt = utf16.index(i, offsetBy:1, limitedBy: utf16.endIndex),
let lo = decodeNibble(utf16[nxt])
let lo = utf16[nxt].decodeHexNibble()
else {
return nil
}
4 changes: 2 additions & 2 deletions Sources/Bluetooth/Extensions/UUID.swift
Original file line number Diff line number Diff line change
@@ -288,10 +288,10 @@ internal extension UInt128 {

/// Parse a UUID string.
init?(uuidString string: String) {
guard let value = Self.bigEndian(uuidString: string) else {
guard let bigEndian = Self.bigEndian(uuidString: string) else {
return nil
}
self.init(bigEndian: value)
self.init(bigEndian: bigEndian)
}

/// Generate UUID string, e.g. `0F4DD6A4-0F71-48EF-98A5-996301B868F9`.
Loading