Skip to content

Commit

Permalink
Update extensions
Browse files Browse the repository at this point in the history
  • Loading branch information
colemancda committed Nov 7, 2024
1 parent ac3640a commit e667e28
Show file tree
Hide file tree
Showing 12 changed files with 194 additions and 475 deletions.
8 changes: 8 additions & 0 deletions Sources/Bluetooth/Data.swift
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,14 @@ public extension DataConvertible {
}
}

public extension Array where Element: DataConvertible {

/// Append data representation into buffer.
static func += <T: DataContainer> (data: inout T, value: Self) {
value.forEach { data += $0 }
}
}

public extension DataContainer {

/// Initialize data with contents of value.
Expand Down
70 changes: 4 additions & 66 deletions Sources/BluetoothGATT/Extensions/Data.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,77 +6,15 @@
// Copyright © 2018 PureSwift. All rights reserved.
//

import Foundation

internal extension Data {

@usableFromInline
func subdataNoCopy(in range: Range<Int>) -> Data {

// stored in heap, can reuse buffer
if count > Data.inlineBufferSize {

return withUnsafeBytes { (buffer: UnsafeRawBufferPointer) in
Data(bytesNoCopy: UnsafeMutableRawPointer(mutating: buffer.baseAddress!.advanced(by: range.lowerBound)),
count: range.count,
deallocator: .none)
}

} else {

// stored in stack, must copy
return subdata(in: range)
}
}

@usableFromInline
func withUnsafeBytes <Result> (in range: Range<Int>, _ block: ((UnsafeRawBufferPointer) throws -> Result)) rethrows -> Result {

return try withUnsafeBytes {
return try block(UnsafeRawBufferPointer(rebasing: $0[range]))
}
}

@usableFromInline
func suffixNoCopy(from index: Int) -> Data {
return subdataNoCopy(in: index ..< count)
}
internal extension DataContainer {

@usableFromInline
func suffixCheckingBounds(from start: Int) -> Data {
func suffixCheckingBounds(from start: Int) -> Self {

if count > start {
return Data(suffix(from: start))
return Self(suffix(from: start))
} else {
return Data()
return Self()
}
}
}

internal extension Data {

/// Size of the inline buffer for `Foundation.Data` used in Swift 5.
///
/// Used to determine wheather data is stored on stack or in heap.
@usableFromInline
static var inlineBufferSize: Int {

// Keep up to date
// https://github.com/apple/swift/blob/aa3e5904f8ba8bf9ae06d96946774d171074f6e5/stdlib/public/Darwin/Foundation/Data.swift#L656
// https://github.com/apple/swift-corelibs-foundation/blob/76068b8caf54f250a7be5336a7c6bb97f55469f8/Sources/Foundation/Data.swift#L649
#if arch(x86_64) || arch(arm64) || arch(s390x) || arch(powerpc64) || arch(powerpc64le)
typealias Buffer = (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) //len //enum
#elseif arch(i386) || arch(arm)
typealias Buffer = (UInt8, UInt8, UInt8, UInt8,
UInt8, UInt8) //len //enum
#elseif os(watchOS) // arm64_32
typealias Buffer = (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) //len //enum
#else
#error("This architecture isn't known. Add it to the 32-bit or 64-bit line.")
#endif

return MemoryLayout<Buffer>.size
}
}
92 changes: 0 additions & 92 deletions Sources/BluetoothGATT/Extensions/DataConvertible.swift

This file was deleted.

77 changes: 73 additions & 4 deletions Sources/BluetoothGATT/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 @@ -29,3 +43,58 @@ internal extension Collection where Element: FixedWidthInteger {
return string
}
}

internal extension FixedWidthInteger {

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

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

init?<C>(hexadecimal utf8: C) where C: Collection, C.Element == UInt8 {
guard utf8.count == MemoryLayout<Self>.size * 2 else {
return nil
}
guard let value = Self(utf8: utf8, radix: 16) else {
return nil
}
self.init(value)
}

/// 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
}
}
Loading

0 comments on commit e667e28

Please sign in to comment.