An open API service indexing awesome lists of open source software.

https://github.com/murphsicles/prost

Protocol Buffers Encoding & Decoding for Zeta
https://github.com/murphsicles/prost

Last synced: 22 days ago
JSON representation

Protocol Buffers Encoding & Decoding for Zeta

Awesome Lists containing this project

README

          

# prost

[![Zeta](https://img.shields.io/badge/Zeta-Language-%23FF6B6B?style=flat-square)](https://zeta-lang.org)
[![zorbs.io](https://img.shields.io/badge/zorbs.io-@proto/prost-%2300C4FF?style=flat-square)](https://zorbs.io/@proto/prost)
[![GitHub](https://img.shields.io/badge/GitHub-murphsicles/prost-%23181717?style=flat-square)](https://github.com/murphsicles/prost)

Protocol Buffers encoding and decoding for Zeta. Prost handles the binary wire format for protobuf messages — the compact, cross-language serialisation protocol used by gRPC, Kafka, and most microservice architectures.

## Quick Start

Add to your `zorb.toml`:

```toml
[dependencies]
@proto/prost = "1.0"
```

Encode and decode Protocol Buffer messages:

```zeta
use @proto/prost::{Message, encoding};

// Define a message type implementing the Message trait
struct MyMessage {
id: i32,
name: String,
tags: Vec,
}

impl Message for MyMessage {
fn encode_raw(&self, buf: &mut impl BufMut) {
encoding::encode_key(1, WireType::Varint, buf);
encoding::encode_varint(self.id as u64, buf);
encoding::encode_key(2, WireType::LengthDelimited, buf);
encoding::encode_string(&self.name, buf);
for tag in &self.tags {
encoding::encode_key(3, WireType::LengthDelimited, buf);
encoding::encode_string(tag, buf);
}
}

fn decode_field(&mut self, tag: u32, wire_type: WireType, buf: &mut impl Buf) -> Result<(), DecodeError> {
match tag {
1 => {
let val = encoding::decode_varint(buf)?;
self.id = val as i32;
Ok(())
}
2 => {
self.name = encoding::decode_string(buf)?;
Ok(())
}
3 => {
let tag_str = encoding::decode_string(buf)?;
self.tags.push(tag_str);
Ok(())
}
_ => Ok(()),
}
}

fn encoded_len(&self) -> usize {
encoding::key_len(1) + encoding::varint_len(self.id as u64)
+ encoding::key_len(2) + encoding::string_len(&self.name)
+ self.tags.iter()
.map(|t| encoding::key_len(3) + encoding::string_len(t))
.sum::()
}

fn clear(&mut self) {
self.id = 0;
self.name.clear();
self.tags.clear();
}
}

fn main() {
let msg = MyMessage {
id: 42,
name: "hello".into(),
tags: vec!["zeta".into(), "protobuf".into()],
};

// Encode
let encoded = msg.encode_to_vec();
print("Encoded: {} bytes\n", encoded.len);

// Decode
let mut decoded = MyMessage::new();
decoded.merge(&encoded).unwrap();
print("Decoded: id={}, name={}\n", decoded.id, decoded.name);
}
```

## Wire Types

| Type | Tag | Description |
|------|-----|-------------|
| `Varint` | 0 | Variable-length integer (int32, int64, uint32, uint64, bool, enum) |
| `Fixed64` | 1 | 64-bit fixed (fixed64, sfixed64, double) |
| `LengthDelimited` | 2 | Length-prefixed data (string, bytes, embedded messages, repeated) |
| `Fixed32` | 5 | 32-bit fixed (fixed32, sfixed32, float) |

## Encoding Utilities

```zeta
use @proto/prost::encoding;

fn main() {
// Varint encoding
let buf = encoding::encode_varint(300).to_vec(); // → [0xAC, 0x02]
let val = encoding::decode_varint(Cursor(buf)); // → 300

// ZigZag encoding (for signed integers)
let buf = encoding::encode_varint(encoding::encode_zigzag(-42));
let zigged = encoding::encode_zigzag(-42); // → 83
let unzigged = encoding::decode_zigzag(zigged); // → -42

// Fixed-size primitives
encoding::encode_fixed32(42u32, buf); // 4 bytes, little-endian
encoding::encode_fixed64(42u64, buf); // 8 bytes, little-endian
encoding::encode_float(3.14f32, buf); // 4 bytes, little-endian
encoding::encode_double(3.14f64, buf); // 8 bytes, little-endian
}
```

## Length-Delimited Messages

For streaming multiple protobuf messages over a single connection:

```zeta
use @proto/prost::encoding::length_delimiter;

fn main() {
// Encode a length-delimited message
let mut buf = Vec::new();
length_delimiter::encode_length_delimiter(msg.encoded_len(), &mut buf).unwrap();
msg.encode_raw(&mut buf);

// Decode the length prefix
let len = length_delimiter::decode_length_delimiter(Cursor(&buf)).unwrap();
// Read `len` bytes for the message body
}
```

## API Overview

| Function / Type | Description |
|----------------|-------------|
| `Message` trait | Core trait: `encode_raw()`, `decode_field()`, `encoded_len()`, `clear()` |
| `encoding::encode_varint(val)` | Encode a varint to bytes |
| `encoding::decode_varint(buf)` | Decode a varint from bytes |
| `encoding::encode_zigzag(val)` | ZigZag encode a signed integer |
| `encoding::decode_zigzag(val)` | ZigZag decode back to signed |
| `encoding::encode_key(tag, wiretype)` | Encode a field key (tag + wire type) |
| `encoding::encode_string(s)` / `decode_string(buf)` | Length-delimited string encoding |
| `encoding::encode_float/double/fixed32/fixed64` | Fixed-width primitive encoding |
| `length_delimiter::encode/decode_length_delimiter()` | Length prefix for streaming |
| `DecodeError` / `EncodeError` | Error types |
| `UnknownEnumValue` | Tracks unrecognized enum values |
| `Name` trait | Type name reflection for proto descriptors |

## Tips

- Use `encoded_len()` to pre-allocate the exact buffer size — much faster than dynamic growth
- For real protobuf usage, pair prost with a `.proto` file compiler for code generation
- The `encoding` module gives you full low-level control over the wire format
- Varint encoding is efficient for small values (< 128) but uses more bytes for large ones — consider fixed32/fixed64 for predictable-size fields

## License

MIT