# flare.grpc.proto

> A module of flare_mlake's API.

``flare.grpc.proto`` -- proto3 wire-format codec.

gRPC payloads are protobuf messages. Until now handler bodies had to
hand-roll ``List[UInt8]`` payloads with no serializer; this module is
that serializer -- the runtime the generated code (or a hand-written
message struct) targets.

proto3 binary wire format (https://protobuf.dev/programming-guides/encoding/):
a message is a flat sequence of ``(tag, value)`` records. The tag is a
varint ``(field_number << 3) | wire_type``:

* 0 ``VARINT``  -- int32/64, uint32/64, sint32/64 (zigzag), bool, enum
* 1 ``I64``     -- fixed64, sfixed64, double
* 2 ``LEN``     -- string, bytes, embedded message, packed repeated
* 5 ``I32``     -- fixed32, sfixed32, float

:class:`ProtoWriter` appends typed fields to an owned buffer;
:class:`ProtoReader` walks a buffer field by field and decodes by wire
type, with :meth:`ProtoReader.skip` for unknown fields (proto3 forward
compatibility). proto3 omits scalar fields equal to their default
(``0`` / ``false`` / empty) on the wire -- the writers here are
low-level (they always emit), so the caller / codegen applies the
default-skip policy.

This is a sans-I/O codec: bytes in, bytes out. No reflection, no
descriptors -- those live in :mod:`flare.grpc.reflection`.

## Structs

### `ProtoWriter`

```mojo
struct ProtoWriter
```

Accumulates proto3-encoded fields into an owned byte buffer.

Example:
```mojo
var w = ProtoWriter()
w.write_string(1, "hello")     # field 1: string
w.write_int64(2, 42)           # field 2: int64
w.write_bool(3, True)          # field 3: bool
var payload = w.take()         # List[UInt8] ready for LPM framing
```

Implements: `Copyable`, `Movable`

Fields:

- `buf: List[UInt8]`

#### `__init__`

```mojo
def __init__(out self)
```

#### `__len__`

```mojo
def __len__(self) -> Int
```

#### `take`

```mojo
def take(mut self) -> List[UInt8]
```

Move the accumulated bytes out, leaving the writer empty.

#### `bytes`

```mojo
def bytes(self) -> List[UInt8]
```

Copy the accumulated bytes (writer stays usable).

#### `write_uint64`

```mojo
def write_uint64(mut self, field: Int, value: UInt64)
```

#### `write_int64`

```mojo
def write_int64(mut self, field: Int, value: Int64)
```

#### `write_sint64`

```mojo
def write_sint64(mut self, field: Int, value: Int64)
```

#### `write_bool`

```mojo
def write_bool(mut self, field: Int, value: Bool)
```

#### `write_enum`

```mojo
def write_enum(mut self, field: Int, value: Int)
```

#### `write_fixed64`

```mojo
def write_fixed64(mut self, field: Int, value: UInt64)
```

#### `write_fixed32`

```mojo
def write_fixed32(mut self, field: Int, value: UInt32)
```

#### `write_double`

```mojo
def write_double(mut self, field: Int, value: Float64)
```

#### `write_float`

```mojo
def write_float(mut self, field: Int, value: Float32)
```

#### `write_bytes`

```mojo
def write_bytes(mut self, field: Int, value: Span[UInt8])
```

A length-delimited field: the tag, the length, then the bytes.

The bytes are copied in one go. A byte at a time is invisible on a
string field and is the whole cost of a large one — Arrow Flight puts
a record batch in `data_body`, so this copy is as big as the data the
server is sending.

#### `write_string`

```mojo
def write_string(mut self, field: Int, value: String)
```

#### `write_message`

```mojo
def write_message(mut self, field: Int, sub: Span[UInt8])
```

Embed a pre-encoded sub-message (its own proto3 bytes).

### `ProtoReader`

```mojo
struct ProtoReader
```

Walks a proto3-encoded buffer field by field.

Typical loop::

    var r = ProtoReader(payload)
    while r.has_more():
        var tw = r.read_tag()       # (field_number, wire_type)
        if tw[0] == 1 and tw[1] == WIRE_LEN:
            var name = r.read_string()
        elif tw[0] == 2 and tw[1] == WIRE_VARINT:
            var age = r.read_int64()
        else:
            r.skip(tw[1])           # unknown field: forward-compat

Implements: `Copyable`, `Movable`

Fields:

- `data: List[UInt8]`
- `pos: Int`

#### `__init__`

```mojo
def __init__(out self, buf: Span[UInt8])
```

Takes its own copy, so the reader outlives the span it was given.

One copy, for the same reason `write_bytes` makes one: a response
being decoded is as large as the payload in it.

#### `has_more`

```mojo
def has_more(self) -> Bool
```

#### `read_tag`

```mojo
def read_tag(mut self) -> Tuple[Int, Int]
```

#### `read_uint64`

```mojo
def read_uint64(mut self) -> UInt64
```

#### `read_int64`

```mojo
def read_int64(mut self) -> Int64
```

#### `read_sint64`

```mojo
def read_sint64(mut self) -> Int64
```

#### `read_bool`

```mojo
def read_bool(mut self) -> Bool
```

#### `read_enum`

```mojo
def read_enum(mut self) -> Int
```

#### `read_fixed64`

```mojo
def read_fixed64(mut self) -> UInt64
```

#### `read_fixed32`

```mojo
def read_fixed32(mut self) -> UInt32
```

#### `read_double`

```mojo
def read_double(mut self) -> Float64
```

#### `read_float`

```mojo
def read_float(mut self) -> Float32
```

#### `read_bytes`

```mojo
def read_bytes(mut self) -> List[UInt8]
```

#### `read_string`

```mojo
def read_string(mut self) -> String
```

#### `skip`

```mojo
def skip(mut self, wire: Int)
```

Advance past one field's value of the given wire type (proto3 unknown-field forward compatibility).

## Aliases

### `WIRE_VARINT`

```mojo
comptime WIRE_VARINT = Int(0)
```

### `WIRE_I64`

```mojo
comptime WIRE_I64 = Int(1)
```

### `WIRE_LEN`

```mojo
comptime WIRE_LEN = Int(2)
```

### `WIRE_I32`

```mojo
comptime WIRE_I32 = Int(5)
```
