|
13 | 13 | public macro magicNumber(_ code: String, parsing input: inout ParserSpan) = |
14 | 14 | #externalMacro(module: "BinaryParsingMacros", type: "MagicNumberStringMacro") |
15 | 15 |
|
| 16 | +/// Parses and validates a magic number or signature of arbitrary length from binary data. |
| 17 | +/// |
| 18 | +/// This macro extends the functionality of `#magicNumber` to support ASCII strings of any length, |
| 19 | +/// not just the 2, 4, or 8 byte limitations of the original macro. It compiles to an optimized |
| 20 | +/// `InlineArray<N, UInt8>` comparison with zero runtime overhead. |
| 21 | +/// |
| 22 | +/// The macro takes an ASCII string literal and generates compile-time code that: |
| 23 | +/// 1. Parses exactly `string.count` bytes from the input span |
| 24 | +/// 2. Compares them against the expected byte values |
| 25 | +/// 3. Throws a `ParsingError` if bytes don't match or insufficient data is available |
| 26 | +/// |
| 27 | +/// ## Usage |
| 28 | +/// |
| 29 | +/// ```swift |
| 30 | +/// // Parse 4-byte magic number |
| 31 | +/// try #magic("test", parsing: &input) |
| 32 | +/// |
| 33 | +/// // Parse single byte |
| 34 | +/// try #magic("A", parsing: &input) |
| 35 | +/// |
| 36 | +/// // Parse longer sequences (e.g., 11 bytes) |
| 37 | +/// try #magic("hello world", parsing: &input) |
| 38 | +/// |
| 39 | +/// ``` |
| 40 | +/// |
| 41 | +/// ## Compile-time Optimization |
| 42 | +/// |
| 43 | +/// The macro generates code equivalent to: |
| 44 | +/// ```swift |
| 45 | +/// _loadAndCheckInlineArrayBytes( |
| 46 | +/// parsing: &input, |
| 47 | +/// expectedBytes: [116, 101, 115, 116] // ASCII values of "test" |
| 48 | +/// ) |
| 49 | +/// ``` |
| 50 | +/// |
| 51 | +/// This leverages Swift 6.2's `InlineArray` and Value Generics for compile-time resolution, |
| 52 | +/// providing the same performance as hand-written byte comparisons. |
| 53 | +/// |
| 54 | +/// ## Error Conditions |
| 55 | +/// |
| 56 | +/// Throws `ParsingError` in these cases: |
| 57 | +/// - Input span has fewer bytes than the magic string length |
| 58 | +/// - Parsed bytes don't match the expected magic string |
| 59 | +/// - Magic string contains non-ASCII characters |
| 60 | +/// - Magic string is empty |
| 61 | +/// |
| 62 | +/// ## Availability |
| 63 | +/// |
| 64 | +/// Requires macOS 26+, iOS 26+, watchOS 26+, tvOS 26+, visionOS 26+ due to `InlineArray` usage. |
| 65 | +/// |
| 66 | +/// ## See Also |
| 67 | +/// |
| 68 | +/// - `#magicNumber(_:parsing:)` for 2/4/8 byte magic numbers using fixed-width integers |
| 69 | +/// - `InlineArray` for the underlying compile-time array implementation |
| 70 | +/// |
| 71 | +/// - Parameter code: An ASCII string literal representing the expected magic bytes |
| 72 | +/// - Parameter input: An inout `ParserSpan` to parse from |
| 73 | +/// - Throws: `ParsingError` if parsing fails or bytes don't match |
16 | 74 | @freestanding(expression) |
17 | 75 | public macro magic(_ code: String, parsing input: inout ParserSpan) = |
18 | 76 | #externalMacro(module: "BinaryParsingMacros", type: "MagicMacro") |
0 commit comments