gin-tonic 0.8.4

main gin-tonic crate - rust protobuf with gin and tonic
Documentation
gin-tonic-0.8.4 has been yanked.

crates.io

gin-tonic

gin-tonic is a Rust protobuf library that lets you use your own types directly on the wire — no manual conversion boilerplate.

It provides:

  • Protobuf serialization and deserialization (like prost)
  • A code generator replacing prost-build
  • A tonic codec implementation
  • A wrapper for tonic-build with extra features
  • A Scalar trait to map any Rust type directly to a protobuf wire type

The problem with other libraries

When you use a UUID in a protobuf message with prost, you write:

message Foo {
  string my_uuid = 1;
}

This generates:

struct Foo {
    my_uuid: String,
}

Your code wants uuid::Uuid, so you end up writing conversions everywhere — and handling parse errors at every call site.

The gin-tonic approach

Annotate your .proto file with the Rust type you want:

import "gin/proto/gin.proto";

message Foo {
  string my_uuid = 1 [(gin_tonic.v1.rust_type) = "uuid::Uuid"];
}

The gin-tonic code generator produces:

struct Foo {
    my_uuid: uuid::Uuid,
}

The conversion is handled once, inside the Scalar trait implementation — not scattered across your codebase.

Built-in UUID support

Two feature flags cover the UUID case out of the box:

Feature Wire type Notes
uuid_string string Parse errors handled in the wire type conversion
uuid_bytes bytes No parse errors; 16-byte fixed representation

Custom types

Implement Scalar for any type to use it as a protobuf field:

impl gin_tonic_core::Scalar<gin_tonic_core::scalars::ProtoString> for MyType {
    const WIRE_TYPE: u8 = gin_tonic_core::WIRE_TYPE_LENGTH_ENCODED;

    fn encode(&self, encoder: &mut impl gin_tonic_core::Encode) {
        encoder.encode_str(&self.to_string());
    }

    fn decode(decoder: &mut impl gin_tonic_core::Decode) -> Result<Self, gin_tonic_core::ProtoError> {
        decoder.decode_string()?.parse().map_err(Into::into)
    }
}

Benchmarks

Measured against prost 0.14.3 on an equivalent message with a UUID, 10 IP addresses, a string, and a nested map with 5 entries on AMD Ryzen AI 7 350.

gin-tonic:

gin_encode    time:   [1.3608 µs 1.3627 µs 1.3654 µs]
gin_decode    time:   [3.0161 µs 3.0198 µs 3.0238 µs]

prost (including From conversions to idiomatic Rust types):

prost_encode  time:   [2.4047 µs 2.4078 µs 2.4111 µs]
prost_decode  time:   [2.8447 µs 2.8497 µs 2.8559 µs]

Decode performance is roughly on par with prost while encoding is about 1.8× faster.

Crates

Crate Description
gin-tonic Main crate — re-exports everything, includes code generator and tonic codec
gin-tonic-core Runtime traits and serialization primitives
gin-tonic-derive Derive macros (Message, Enumeration, OneOf)