Skip to content

Commit

Permalink
Merge pull request #168 from PureSwift/feature/remove-bitmaskoptionset
Browse files Browse the repository at this point in the history
Deprecate `BitMaskOption`
  • Loading branch information
colemancda authored Nov 6, 2024
2 parents 2e7b503 + 2cd18c5 commit f6fa6a7
Show file tree
Hide file tree
Showing 13 changed files with 349 additions and 216 deletions.
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

0 comments on commit f6fa6a7

Please sign in to comment.