jetstream 16.0.0

Jetstream is a RPC framework for Rust, based on the 9P protocol and QUIC.
Documentation
# Swift WireFormat Implementation Spec

This specification defines the rules for implementing the JetStream WireFormat in Swift. The wire format is based on the [9P2000.L](http://man.cat-v.org/plan_9/5/0intro) protocol. All rules reference the base wireformat specification in `wireformat.md`. The implementation MUST produce byte-identical output to the Rust implementation for all types and MUST be wire-compatible with any compliant 9P2000.L implementation.

r[jetstream.wireformat.swift.9p-compat]
9P2000.L Wire Compatibility

The Swift implementation MUST produce wire output that is byte-identical to the Rust 9P-based JetStream implementation. This means:
- All multi-byte integers MUST use little-endian byte order (matching 9P2000.L conventions).
- Strings MUST use the 9P "string[s]" encoding: a UInt16 byte count followed by UTF-8 data.
- Data buffers MUST use the 9P "data[count]" encoding: a UInt32 byte count followed by raw bytes.
- The Swift implementation MUST be interoperable with the Rust `jetstream_wireformat` crate.

## Core Abstractions

r[jetstream.wireformat.swift.protocol]
WireFormat Protocol

Implement a `WireFormat` protocol with three required methods:

```swift
protocol WireFormat {
    func byteSize() -> UInt32
    func encode(writer: inout BinaryWriter) throws
    static func decode(reader: inout BinaryReader) throws -> Self
}
```

All type implementations MUST conform to this protocol. `encode` and `decode` MUST throw on I/O errors or invalid data.

r[jetstream.wireformat.swift.reader]
BinaryReader Struct

Implement a `BinaryReader` struct that reads from a `Data` object with a cursor position:

```swift
struct BinaryReader {
    private let data: Data
    private(set) var offset: Int

    init(data: Data)
    mutating func readBytes(count: Int) throws -> Data
    mutating func readU8() throws -> UInt8
    mutating func readU16() throws -> UInt16  // little-endian
    mutating func readU32() throws -> UInt32  // little-endian
    mutating func readU64() throws -> UInt64  // little-endian
    mutating func readI16() throws -> Int16   // little-endian
    mutating func readI32() throws -> Int32   // little-endian
    mutating func readI64() throws -> Int64   // little-endian
    mutating func readF32() throws -> Float   // little-endian
    mutating func readF64() throws -> Double  // little-endian
    var remaining: Int { get }
}
```

The reader MUST throw if attempting to read beyond the data. Use `withUnsafeBytes` and `littleEndian` conversions for multi-byte reads.

r[jetstream.wireformat.swift.writer]
BinaryWriter Struct

Implement a `BinaryWriter` struct that writes to a growable `Data` buffer:

```swift
struct BinaryWriter {
    private(set) var data: Data

    init(capacity: Int = 256)
    mutating func writeBytes(_ bytes: Data)
    mutating func writeU8(_ value: UInt8)
    mutating func writeU16(_ value: UInt16)  // little-endian
    mutating func writeU32(_ value: UInt32)  // little-endian
    mutating func writeU64(_ value: UInt64)  // little-endian
    mutating func writeI16(_ value: Int16)   // little-endian
    mutating func writeI32(_ value: Int32)   // little-endian
    mutating func writeI64(_ value: Int64)   // little-endian
    mutating func writeF32(_ value: Float)   // little-endian
    mutating func writeF64(_ value: Double)  // little-endian
}
```

Use `withUnsafeBytes(of: value.littleEndian)` for converting multi-byte values to little-endian bytes before appending to data.

## Primitive Types

r[jetstream.wireformat.swift.u8]
Encode/Decode UInt8

Encode as a single byte. Decode by reading one byte. Maps to Swift `UInt8`. Implements **WF-U8**.

r[jetstream.wireformat.swift.u16]
Encode/Decode UInt16

Encode using `UInt16.littleEndian`. Decode using `UInt16(littleEndian:)`. Maps to Swift `UInt16`. Implements **WF-U16**.

r[jetstream.wireformat.swift.u32]
Encode/Decode UInt32

Encode using `UInt32.littleEndian`. Decode using `UInt32(littleEndian:)`. Maps to Swift `UInt32`. Implements **WF-U32**.

r[jetstream.wireformat.swift.u64]
Encode/Decode UInt64

Encode using `UInt64.littleEndian`. Decode using `UInt64(littleEndian:)`. Maps to Swift `UInt64`. Implements **WF-U64**.

r[jetstream.wireformat.swift.u128]
Encode/Decode UInt128

Swift does not have a native UInt128 type (prior to Swift 6). Implement using a custom struct or tuple `(low: UInt64, high: UInt64)`. Encode the lower 64 bits first (bytes 0-7) as UInt64 LE, then the upper 64 bits (bytes 8-15) as UInt64 LE. On decode, read low then high UInt64 values. Implements **WF-U128**.

Note: If targeting Swift 6+, the built-in `UInt128` type may be used directly with `littleEndian` conversion.

r[jetstream.wireformat.swift.i16]
Encode/Decode Int16

Encode using `Int16.littleEndian`. Decode using `Int16(littleEndian:)`. Maps to Swift `Int16`. Implements **WF-I16**.

r[jetstream.wireformat.swift.i32]
Encode/Decode Int32

Encode using `Int32.littleEndian`. Decode using `Int32(littleEndian:)`. Maps to Swift `Int32`. Implements **WF-I32**.

r[jetstream.wireformat.swift.i64]
Encode/Decode Int64

Encode using `Int64.littleEndian`. Decode using `Int64(littleEndian:)`. Maps to Swift `Int64`. Implements **WF-I64**.

r[jetstream.wireformat.swift.i128]
Encode/Decode Int128

Similar to UInt128, use a custom struct or `(low: UInt64, high: Int64)` representation. Encode: write lower 64 bits as UInt64 LE, then upper 64 bits as Int64 LE (preserving the sign). Decode: read UInt64 low, Int64 high. Implements **WF-I128**.

Note: If targeting Swift 6+, the built-in `Int128` type may be used.

r[jetstream.wireformat.swift.f32]
Encode/Decode Float

Encode: convert `Float` to its bit pattern via `Float.bitPattern` (UInt32), encode as UInt32 LE. Decode: read UInt32 LE, convert to Float via `Float(bitPattern:)`. Maps to Swift `Float`. Implements **WF-F32**.

r[jetstream.wireformat.swift.f64]
Encode/Decode Double

Encode: convert `Double` to its bit pattern via `Double.bitPattern` (UInt64), encode as UInt64 LE. Decode: read UInt64 LE, convert to Double via `Double(bitPattern:)`. Maps to Swift `Double`. Implements **WF-F64**.

r[jetstream.wireformat.swift.bool]
Encode/Decode Bool

Encode `false` as `0x00` and `true` as `0x01`. Decode MUST reject any value other than 0 or 1 by throwing an error. Maps to Swift `Bool`. Implements **WF-BOOL**.

r[jetstream.wireformat.swift.unit]
Encode/Decode Void

The unit type writes and reads zero bytes. May be represented as `Void` or an empty struct in Swift. Implements **WF-UNIT**.

## String

r[jetstream.wireformat.swift.string]
Encode/Decode String

Encode: convert the `String` to UTF-8 bytes via `.utf8`. If the byte count exceeds 65,535, throw an error. Write the byte count as UInt16 LE, then write the UTF-8 bytes.

Decode: read UInt16 length N, read N bytes, decode as UTF-8 via `String(data:encoding:.utf8)`. If decoding fails, throw an invalid data error. Maps to Swift `String`. Implements **WF-STRING**.

## Collections

r[jetstream.wireformat.swift.array]
Encode/Decode Array

Use Swift `Array<T>` (`[T]`). Encode: if count > 65,535, throw. Write count as UInt16 LE, encode each element. Decode: read UInt16 count, decode that many elements into an array. Implements **WF-VEC**.

r[jetstream.wireformat.swift.data]
Encode/Decode Data (byte buffer)

Use Swift `Data` for the Data type. Encode: write byte count as UInt32 LE, then write raw bytes. Decode: read UInt32 length, reject if > 33,554,432 (32 MB), read that many bytes. If fewer than N bytes are available, throw an unexpected EOF error. Implements **WF-DATA**.

r[jetstream.wireformat.swift.dict]
Encode/Decode Dictionary (ordered)

Since Swift `Dictionary` is unordered, use a sorted array of key-value tuples or a custom `OrderedDictionary` type that maintains sorted order. Encode: if count > 65,535, throw. Write count as UInt16 LE, encode key-value pairs in sorted key order. Decode: read UInt16 count, decode key-value pairs, insert into collection. Entries MUST be emitted in sorted key order when encoding. Implements **WF-MAP**.

r[jetstream.wireformat.swift.set]
Encode/Decode Set (ordered)

Since Swift `Set` is unordered, encode elements in sorted order. May use a custom `OrderedSet` type or sort before encoding. Encode: if count > 65,535, throw. Write count as UInt16 LE, encode elements in sorted order. Decode: read UInt16 count, decode elements. Implements **WF-SET**.

## Option Type

r[jetstream.wireformat.swift.optional]
Encode/Decode Optional

Use Swift `Optional<T>` (`T?`). Encode: if `nil`, write `0x00`; if `.some(value)`, write `0x01` followed by the encoded value. Decode: read UInt8 tag; if 0, return `nil`; if 1, decode and return the value; otherwise throw an error. Implements **WF-OPTION**.

## Composite Types

r[jetstream.wireformat.swift.struct]
Encode/Decode Structs

Represent structs as Swift structs conforming to the `WireFormat` protocol. Fields MUST be encoded and decoded sequentially in declaration order (matching the Rust struct field order). There is no length prefix or field name on the wire. Implements **WF-STRUCT**.

r[jetstream.wireformat.swift.enum]
Encode/Decode Enums

Use Swift enums with associated values. Each variant is assigned a UInt8 index (0-based) in declaration order. Encode: write the variant index as UInt8, then encode the variant's associated values. Decode: read UInt8 variant index, decode the variant's associated values, construct the enum case. Throw on unknown variant index. Implements **WF-ENUM**.

Example:
```swift
enum Message: WireFormat {
    case ping                      // variant 0
    case text(content: String)     // variant 1
    case binary(data: Data)        // variant 2
}
```

## Network Types

r[jetstream.wireformat.swift.ipv4]
Encode/Decode IPv4

Represent using a struct with 4 bytes or use `in_addr` from `Darwin`/`Glibc`. Encode: write the 4 octets directly. Decode: read 4 bytes. May provide convenience conversion to/from string representation. Implements **WF-IPV4**.

r[jetstream.wireformat.swift.ipv6]
Encode/Decode IPv6

Represent using a struct with 16 bytes or use `in6_addr` from `Darwin`/`Glibc`. Encode: write the 16 octets directly. Decode: read 16 bytes. Implements **WF-IPV6**.

r[jetstream.wireformat.swift.ipaddr]
Encode/Decode IpAddr

Represent as a Swift enum:
```swift
enum IpAddr: WireFormat {
    case v4(IPv4Address)   // tag = 4
    case v6(IPv6Address)   // tag = 6
}
```

Note: the tag values are `4` and `6` (NOT 0 and 1 like standard enum encoding). Encode: write UInt8 tag (4 or 6), then write address bytes. Decode: read UInt8 tag, read address bytes. Throw on invalid tag. Implements **WF-IPADDR**.

r[jetstream.wireformat.swift.sockaddr]
Encode/Decode SocketAddr

Represent as a Swift enum:
```swift
enum SocketAddr: WireFormat {
    case v4(ip: IPv4Address, port: UInt16)   // tag = 4
    case v6(ip: IPv6Address, port: UInt16)   // tag = 6
}
```

Encode: write UInt8 tag (4 or 6), encode IP address, encode port as UInt16 LE. Decode: read tag, decode address, decode port. Note: SocketAddrV6's flow info and scope ID are NOT on the wire (set to 0 on decode). Throw on invalid tag. Implements **WF-SOCKADDR**.

## Time

r[jetstream.wireformat.swift.systime]
Encode/Decode SystemTime

Represent as Swift `Date`. Encode: compute milliseconds since Unix epoch via `Date.timeIntervalSince1970 * 1000`, cast to UInt64, encode as UInt64 LE. Decode: read UInt64, construct `Date(timeIntervalSince1970: Double(millis) / 1000.0)`. Implements **WF-SYSTIME**.

## Error Types

r[jetstream.wireformat.swift.error-inner]
ErrorInner Struct

Implement an `ErrorInner` struct conforming to `WireFormat`:
- `message: String` — encoded as WF-STRING
- `code: String?` — encoded as WF-OPTION of WF-STRING
- `help: String?` — encoded as WF-OPTION of WF-STRING
- `url: String?` — encoded as WF-OPTION of WF-STRING

Encode and decode these fields sequentially in the order listed. Implements **WF-ERR-INNER**.

r[jetstream.wireformat.swift.backtrace]
Backtrace Struct

Implement a `Backtrace` struct conforming to `WireFormat`:
- `internTable: [String]` — encoded as WF-VEC of WF-STRING
- `frames: [Frame]` — encoded as WF-VEC of WF-FRAME

Index 0 of the intern table is reserved for the empty string "". Implements **WF-BACKTRACE**.

r[jetstream.wireformat.swift.frame]
Frame Struct

Implement a `Frame` struct conforming to `WireFormat` with fields encoded in this exact order:
1. `msg: String` — WF-STRING
2. `name: UInt16` — WF-U16 (intern table index)
3. `target: UInt16` — WF-U16 (intern table index)
4. `module: UInt16` — WF-U16 (intern table index)
5. `file: UInt16` — WF-U16 (intern table index)
6. `line: UInt16` — WF-U16
7. `fields: [FieldPair]` — WF-VEC of WF-FIELDPAIR
8. `level: Level` — WF-LEVEL (custom codec)

Implements **WF-FRAME**.

r[jetstream.wireformat.swift.fieldpair]
FieldPair Struct

Implement a `FieldPair` struct conforming to `WireFormat`:
- `key: UInt16` — WF-U16 (intern table index)
- `value: UInt16` — WF-U16 (intern table index)

Implements **WF-FIELDPAIR**.

r[jetstream.wireformat.swift.level]
Level Enum

Define a `Level` enum with raw UInt8 values:

```swift
enum Level: UInt8, WireFormat {
    case trace = 0
    case debug = 1
    case info = 2
    case warn = 3
    case error = 4
}
```

Encode as UInt8. Decode: read UInt8, convert to Level via `Level(rawValue:)`, throw on invalid value. Implements **WF-LEVEL**.

r[jetstream.wireformat.swift.error]
JetStreamError

Implement a `JetStreamError` class/struct conforming to both `WireFormat` and Swift's `Error` protocol:
- `inner: ErrorInner` — encoded per SW-WF-ERR-INNER
- `backtrace: Backtrace` — encoded per SW-WF-BACKTRACE

Encode: encode inner, then backtrace. Decode: decode inner, then backtrace. Implements **WF-ERROR**.

## Package Structure

r[jetstream.wireformat.swift.package]
Swift Package

The Swift implementation MUST be organized as a Swift Package with:
- Source files under `Sources/JetStreamWireFormat/`
- Test files under `Tests/JetStreamWireFormatTests/`
- A `Package.swift` manifest

The package MUST support Apple platforms (iOS 15+, macOS 12+) and Linux.

## Testing Requirements

r[jetstream.wireformat.swift.test-roundtrip]
Round-trip Testing

Every type implementation MUST have tests that verify: encode(value) followed by decode(encodedBytes) produces an equal value. Tests MUST cover edge cases including empty strings, empty arrays, maximum lengths, nil values, and boundary values for numeric types.

r[jetstream.wireformat.swift.test-compat]
Cross-language Compatibility Testing

The Swift implementation MUST be tested against known byte sequences produced by the Rust implementation to verify binary compatibility. Test vectors SHOULD be generated from the Rust tests and verified in Swift.

r[jetstream.wireformat.swift.test-error]
Error Handling Tests

Tests MUST verify that decoding invalid data throws appropriate errors:
- Invalid bool byte (not 0 or 1)
- Invalid Optional tag (not 0 or 1)
- Invalid enum variant index (out of range)
- Invalid Level byte (> 4)
- String length exceeding 65,535
- Data length exceeding 32 MB
- Unexpected EOF (truncated data)
- Invalid UTF-8 in strings
- Invalid IP address tag (not 4 or 6)