-
-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #172 from PureSwift/feature/macros
Add macros
- Loading branch information
Showing
11 changed files
with
428 additions
and
50 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
// | ||
// Address.swift | ||
// Bluetooth | ||
// | ||
// Created by Alsey Coleman Miller on 1/9/25. | ||
// | ||
|
||
import Foundation | ||
import SwiftSyntaxMacros | ||
import SwiftSyntax | ||
|
||
struct BluetoothAddressMacro: ExpressionMacro { | ||
|
||
static func expansion( | ||
of node: some FreestandingMacroExpansionSyntax, | ||
in context: some MacroExpansionContext | ||
) throws(Error) -> ExprSyntax { | ||
|
||
guard let argument = node.arguments.first?.expression, | ||
let segments = argument.as(StringLiteralExprSyntax.self)?.segments, | ||
segments.count == 1, | ||
case .stringSegment(let literalSegment)? = segments.first else { | ||
throw .requiresStaticStringLiteral | ||
} | ||
|
||
guard let _ = Self.parse(literalSegment.content.text) else { | ||
throw .invalidString("\(argument)") | ||
} | ||
|
||
return "BluetoothAddress(rawValue: \(argument))!" | ||
} | ||
|
||
/// Initialize a Bluetooth Address from its big endian string representation (e.g. `00:1A:7D:DA:71:13`). | ||
static func parse<S: StringProtocol>(_ rawValue: S) -> ByteValue? { | ||
|
||
// verify string length | ||
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 = characters.split(whereSeparator: { $0 == separator }) | ||
|
||
guard components.count == 6 | ||
else { return nil } | ||
|
||
for (index, subsequence) in components.enumerated() { | ||
|
||
guard subsequence.count == 2, | ||
let byte = UInt8(hexadecimal: subsequence) | ||
else { return nil } | ||
|
||
withUnsafeMutablePointer(to: &bytes) { | ||
$0.withMemoryRebound(to: UInt8.self, capacity: 6) { | ||
$0.advanced(by: index).pointee = byte | ||
} | ||
} | ||
} | ||
|
||
return bytes | ||
} | ||
} | ||
|
||
// MARK: - Supporting Types | ||
|
||
extension BluetoothAddressMacro { | ||
|
||
/// Raw Bluetooth Address 6 byte (48 bit) value. | ||
typealias ByteValue = (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) | ||
|
||
enum Error: Swift.Error { | ||
case requiresStaticStringLiteral | ||
case invalidString(String) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// | ||
// BluetoothUUID.swift | ||
// Bluetooth | ||
// | ||
// Created by Alsey Coleman Miller on 1/9/25. | ||
// | ||
|
||
import Foundation | ||
import SwiftSyntaxMacros | ||
import SwiftSyntax | ||
|
||
struct BluetoothUUIDMacro: ExpressionMacro { | ||
|
||
static func expansion( | ||
of node: some FreestandingMacroExpansionSyntax, | ||
in context: some MacroExpansionContext | ||
) throws(Error) -> ExprSyntax { | ||
|
||
guard let argument = node.arguments.first?.expression, | ||
let segments = argument.as(StringLiteralExprSyntax.self)?.segments, | ||
segments.count == 1, | ||
case .stringSegment(let literalSegment)? = segments.first else { | ||
throw .requiresStaticStringLiteral | ||
} | ||
|
||
guard validate(literalSegment.content.text) else { | ||
throw .invalidString("\(argument)") | ||
} | ||
|
||
return "BluetoothUUID(rawValue: \(argument))!" | ||
} | ||
|
||
static func validate(_ rawValue: String) -> Bool { | ||
switch rawValue.utf8.count { | ||
case 4: | ||
guard let _ = UInt16(hexadecimal: rawValue) | ||
else { return false } | ||
return true | ||
case 8: | ||
guard let _ = UInt32(hexadecimal: rawValue) | ||
else { return false } | ||
return true | ||
case 36: | ||
guard let _ = UUID(uuidString: rawValue) | ||
else { return false } | ||
return true | ||
default: | ||
return false | ||
} | ||
} | ||
} | ||
|
||
// MARK: - Supporting Types | ||
|
||
extension BluetoothUUIDMacro { | ||
|
||
enum Error: Swift.Error { | ||
case requiresStaticStringLiteral | ||
case invalidString(String) | ||
} | ||
} |
Oops, something went wrong.