Skip to content

Commit

Permalink
Merge pull request #164 from PureSwift/feature/UInt128
Browse files Browse the repository at this point in the history
Use standard library `UInt128`
  • Loading branch information
colemancda authored Nov 4, 2024
2 parents 8f75e18 + 444ab3f commit b53a6ec
Show file tree
Hide file tree
Showing 12 changed files with 662 additions and 226 deletions.
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
Expand All @@ -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
Expand Up @@ -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"
Expand Down
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
Expand Up @@ -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
Expand All @@ -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
Expand Down
53 changes: 22 additions & 31 deletions Sources/Bluetooth/BluetoothUUID.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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).
Expand All @@ -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)
Expand All @@ -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) {
Expand Down Expand Up @@ -212,7 +205,6 @@ public extension BluetoothUUID {
}
}

#if canImport(Foundation)
internal extension UUID {

@inline(__always)
Expand Down Expand Up @@ -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,
Expand All @@ -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 }
Expand All @@ -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) {
Expand Down Expand Up @@ -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
Expand Up @@ -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
Expand All @@ -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
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/Bluetooth/Extensions/UUID.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down
Loading

0 comments on commit b53a6ec

Please sign in to comment.