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

Deprecate BitMaskOption #168

Merged
merged 12 commits into from
Nov 6, 2024
5 changes: 3 additions & 2 deletions .github/workflows/swift-arm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ jobs:
uses: actions/checkout@v2
- name: Swift Version
run: swift --version
- name: Build
- name: Build Bluetooth
run: swift build --triple armv6m-apple-none-macho --configuration release --verbose -Xswiftc -enable-experimental-feature -Xswiftc Embedded -Xswiftc -disable-stack-protector -Xcc -D__MACH__ -Xcc -ffreestanding -Xcc -mcpu=cortex-m0plus -Xcc -mthumb --target Bluetooth

- name: Build BluetoothGAP
run: swift build --triple armv6m-apple-none-macho --configuration release --verbose -Xswiftc -enable-experimental-feature -Xswiftc Embedded -Xswiftc -disable-stack-protector -Xcc -D__MACH__ -Xcc -ffreestanding -Xcc -mcpu=cortex-m0plus -Xcc -mthumb --target BluetoothGAP
38 changes: 19 additions & 19 deletions Sources/Bluetooth/Address.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,27 +86,33 @@ extension BluetoothAddress: ByteSwap {

// MARK: - RawRepresentable

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

/// Initialize a Bluetooth Address from its big endian string representation (e.g. `00:1A:7D:DA:71:13`).
public init?(rawValue: String) {
self.init(rawValue)
}

/// Initialize a Bluetooth Address from its big endian string representation (e.g. `00:1A:7D:DA:71:13`).
internal init?<S: StringProtocol>(_ rawValue: S) {

// verify string length
guard rawValue.utf8.count == 17
let characters = rawValue.utf8
guard characters.count == 17,
let separator = ":".utf8.first
else { return nil }

var bytes: ByteValue = (0, 0, 0, 0, 0, 0)

let components = rawValue.split(whereSeparator: { $0 == ":" })
let components = characters.split(whereSeparator: { $0 == separator })

guard components.count == 6
else { return nil }

for (index, string) in components.enumerated() {
for (index, subsequence) in components.enumerated() {

guard string.utf8.count == 2,
let byte = UInt8(string, radix: 16)
guard subsequence.count == 2,
let byte = UInt8(hexadecimal: subsequence)
else { return nil }

withUnsafeMutablePointer(to: &bytes) {
Expand All @@ -121,19 +127,6 @@ extension BluetoothAddress: RawRepresentable {

/// Convert a Bluetooth Address to its big endian string representation (e.g. `00:1A:7D:DA:71:13`).
public var rawValue: String {
_description
}
}
#endif

// MARK: - CustomStringConvertible

extension BluetoothAddress: CustomStringConvertible {

public var description: String { _description }

/// Convert a Bluetooth Address to its big endian string representation (e.g. `00:1A:7D:DA:71:13`).
internal var _description: String {
let bytes = self.bigEndian.bytes
return bytes.0.toHexadecimal()
+ ":" + bytes.1.toHexadecimal()
Expand All @@ -144,6 +137,13 @@ extension BluetoothAddress: CustomStringConvertible {
}
}

// MARK: - CustomStringConvertible

extension BluetoothAddress: CustomStringConvertible {

public var description: String { rawValue }
}

// MARK: - Data

public extension BluetoothAddress {
Expand Down
3 changes: 2 additions & 1 deletion Sources/Bluetooth/BitMaskOption.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
/// Enum that represents a bit mask flag / option.
///
/// Basically `Swift.OptionSet` for enums.
@available(*, deprecated, message: "Use OptionSet instead")
public protocol BitMaskOption: RawRepresentable, Hashable, CaseIterable where RawValue: FixedWidthInteger { }

public extension Sequence where Element: BitMaskOption {
Expand Down Expand Up @@ -40,7 +41,7 @@ public extension BitMaskOption {
/// Integer-backed array type for `BitMaskOption`.
///
/// The elements are packed in the integer with bitwise math and stored on the stack.
@frozen
@available(*, deprecated, message: "Use OptionSet instead")
public struct BitMaskOptionSet <Element: BitMaskOption>: RawRepresentable {

public typealias RawValue = Element.RawValue
Expand Down
90 changes: 51 additions & 39 deletions Sources/Bluetooth/Extensions/Hexadecimal.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,26 @@
internal extension FixedWidthInteger {

func toHexadecimal() -> String {

var string = String(self, radix: 16)
while string.utf8.count < (MemoryLayout<Self>.size * 2) {
let length = MemoryLayout<Self>.size * 2
var string: String
#if hasFeature(Embedded) || (canImport(Darwin) && DEBUG)
string = ""
string.reserveCapacity(length)
self.bigEndian.bytes.forEach { byte in
string.append(String(format: "%02X", length: 2, byte)!)
}
#else // Linux and non-Embedded release builds use Swift StdLib
string = String(self, radix: 16, uppercase: true)
// Add Zero padding
while string.utf8.count < length {
string = "0" + string
}
return string.uppercased()
#endif
assert(string.utf8.count == length)
#if !hasFeature(Embedded)
assert(string == string.uppercased(), "String should be uppercased")
#endif
return string
}
}

Expand All @@ -30,65 +44,62 @@ internal extension Collection where Element: FixedWidthInteger {
}
}

internal extension UInt {
internal extension FixedWidthInteger {

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
init?<S: StringProtocol>(parse string: S, radix: Self) {
#if !hasFeature(Embedded)
let string = string.uppercased()
#endif
self.init(utf8: string.utf8, radix: radix)
}
}

internal extension UInt16 {

init?(hexadecimal string: String) {
init?<S: StringProtocol>(hexadecimal string: S) {
guard string.utf8.count == MemoryLayout<Self>.size * 2 else {
return nil
}
#if hasFeature(Embedded) || DEBUG
guard let value = UInt(parse: string, radix: 16) else {
guard let value = Self(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.utf8.count == MemoryLayout<Self>.size * 2 else {
init?<C>(hexadecimal utf8: C) where C: Collection, C.Element == UInt8 {
guard utf8.count == MemoryLayout<Self>.size * 2 else {
return nil
}
#if hasFeature(Embedded) || DEBUG
guard let value = UInt(parse: string, radix: 16) else {
guard let value = Self(utf8: utf8, radix: 16) else {
return nil
}
self.init(value)
#else
self.init(string, radix: 16)
}

/// Expects uppercase UTF8 data.
init?<C>(utf8: C, radix: Self) where C: Collection, C.Element == UInt8 {
#if !hasFeature(Embedded) && DEBUG
assert(String(decoding: utf8, as: UTF8.self) == String(decoding: utf8, as: UTF8.self).uppercased(), "Expected uppercase string")
#endif
let digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".utf8
var result = Self(0)
for character in utf8 {
if let stringIndex = digits.enumerated().first(where: { $0.element == character })?.offset {
let val = Self(stringIndex)
if val >= radix {
return nil
}
result = result * radix + val
} else {
return nil
}
}
self = result
}
}

#if !hasFeature(Embedded)
internal extension String.UTF16View.Element {

// Convert 0 ... 9, a ... f, A ...F to their decimal value,
Expand Down Expand Up @@ -143,3 +154,4 @@ internal extension [UInt8] {

}
}
#endif
19 changes: 10 additions & 9 deletions Sources/Bluetooth/Extensions/Integer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,11 @@ internal extension UInt16 {

/// Initializes value from two bytes.
init(bytes: (UInt8, UInt8)) {

self = unsafeBitCast(bytes, to: UInt16.self)
}

/// Converts to two bytes.
var bytes: (UInt8, UInt8) {

return unsafeBitCast(self, to: (UInt8, UInt8).self)
}
}
Expand All @@ -29,13 +27,11 @@ internal extension UInt32 {

/// Initializes value from four bytes.
init(bytes: (UInt8, UInt8, UInt8, UInt8)) {

self = unsafeBitCast(bytes, to: UInt32.self)
}

/// Converts to four bytes.
var bytes: (UInt8, UInt8, UInt8, UInt8) {

return unsafeBitCast(self, to: (UInt8, UInt8, UInt8, UInt8).self)
}
}
Expand All @@ -44,13 +40,11 @@ internal extension UInt64 {

/// Initializes value from four bytes.
init(bytes: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8)) {

self = unsafeBitCast(bytes, to: UInt64.self)
}

/// Converts to eight bytes.
var bytes: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) {

return unsafeBitCast(self, to: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8).self)
}
}
Expand All @@ -59,7 +53,6 @@ internal extension UInt8 {

/// Initialize a byte from 2 bit enums.
static func bit2(_ enum1: UInt8, _ enum2: UInt8, _ enum3: UInt8, _ enum4: UInt8) -> UInt8 {

var value: UInt8 = 0
value += enum1 << 6
value += enum2 << 4
Expand All @@ -70,11 +63,19 @@ internal extension UInt8 {

/// Get 2 bit values from a byte.
func bit2() -> (UInt8, UInt8, UInt8, UInt8) {

return (self >> 6, (self << 2) >> 6, (self << 4) >> 6, (self << 6) >> 6)
}
}

internal extension BinaryInteger {

@inlinable
var bytes: [UInt8] {
var mutableValueCopy = self
return withUnsafeBytes(of: &mutableValueCopy) { Array($0) }
}
}

#if canImport(Foundation)
internal extension UInt64 {

Expand Down Expand Up @@ -136,4 +137,4 @@ internal extension UInt64 {
}
}
}
#endif
#endif
28 changes: 28 additions & 0 deletions Sources/Bluetooth/Extensions/String.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
// Created by Alsey Coleman Miller on 11/4/24.
//

#if canImport(Darwin)
import Darwin
#endif

internal extension String {

/// Initialize from UTF8 data.
Expand All @@ -19,4 +23,28 @@ internal extension String {
}
#endif
}

#if hasFeature(Embedded)
// Can't use `CVarArg` in Embedded Swift
init?(format: String, length: Int, _ value: UInt8) {
var cString: [CChar] = .init(repeating: 0, count: length + 1)
guard _snprintf_uint8_t(&cString, cString.count, format, value) >= 0 else {
return nil
}
self.init(cString: cString)
}
#elseif canImport(Darwin)
init?<T: CVarArg>(format: String, length: Int, _ value: T) {
var cString: [CChar] = .init(repeating: 0, count: length + 1)
guard snprintf(ptr: &cString, cString.count, format, value) >= 0 else {
return nil
}
self.init(cString: cString)
}
#endif
}

#if hasFeature(Embedded)
@_silgen_name("snprintf")
internal func _snprintf_uint8_t(_ pointer: UnsafeMutablePointer<CChar>, _ length: Int, _ format: UnsafePointer<CChar>, _ arg: UInt8) -> Int32
#endif
Loading
Loading