Skip to content

Protobuf

Shizuku provides Protocol Buffers serialization support through the protobuf feature flag. This integration uses prost for serialization and deserialization.

Installation

  1. Add the protobuf feature to your Shizuku dependency in Cargo.toml:

    Cargo.toml
    [dependencies]
    shizuku = { version = "0.0.2-alpha.2", features = ["protobuf"] }
  2. Add prost-build to your build dependencies:

    Cargo.toml
    [build-dependencies]
    prost-build = "0.13"
  3. Create a build.rs file in your project root to compile .proto files:

    /build.rs
    fn main() {
    prost_build::compile_protos(&["src/proto/user.proto"], &["src/proto"])
    .unwrap();
    }
  4. Create your .proto files in the specified directory (e.g., src/proto/user.proto):

    src/proto/user.proto
    syntax = "proto3";
    package user;
    message User {
    string id = 1;
    string name = 2;
    string email = 3;
    }
  5. Create a module file to include the generated code (e.g., src/user.rs):

    src/user.rs
    // Include the generated protobuf code
    pub mod proto {
    include!(concat!(env!("OUT_DIR"), "/user.rs"));
    }
    // Re-export the types you want to use directly
    pub use proto::User;
    pub use proto::CreateUserRequest;
    pub use proto::CreateUserResponse;
    // Implement serialization and deserialization for the types
    use shizuku::{protobuf_ser, protobuf_des};
    protobuf_ser!(User);
    protobuf_des!(User);
    protobuf_ser!(CreateUserRequest);
    protobuf_des!(CreateUserResponse);

Usage

The Protobuf integration provides two macros for implementing serialization traits:

  • protobuf_ser: Implements ByteSerialize for Protobuf serialization
  • protobuf_des: Implements ByteDeserialize for Protobuf deserialization

Using in Services

The Protobuf serialization works seamlessly with NATS services:

src/user.rs
use shizuku::{protobuf_ser, protobuf_des, NatsRpcCallTrait};
include!(concat!(env!("OUT_DIR"), "/user.rs"));
impl NatsRpcCallTrait<CreateUserResponse> for CreateUserRequest {
fn subject() -> (NatsSubjectPath, PhantomData<CreateUserResponse>) {
(subject_path!["user", "create"], PhantomData)
}
}
protobuf_ser!(CreateUserRequest);
protobuf_des!(CreateUserResponse);

Using with JetStream

You can use Protobuf serialization for JetStream events and consumers:

src/order.rs
use shizuku::{protobuf_ser, protobuf_des, DynamicSubjectMessage, JetStreamMessageSendTrait};
include!(concat!(env!("OUT_DIR"), "/order.rs"));
// Implement serialization
protobuf_ser!(OrderCreatedEvent);
protobuf_des!(OrderData);
src/app.rs
use shizuku::{DynamicSubjectMessage, JetStreamMessageSendTrait};
use shizuku::jetstream::FinalJetStreamProcessor;
use crate::order::{OrderCreatedEvent, OrderData};
// Implement dynamic subject for the event
impl DynamicSubjectMessage for OrderCreatedEvent {
fn subject(&self) -> NatsSubjectPath {
subject_path!["order", "created", &self.order_id]
}
}
// The trait is automatically implemented
impl JetStreamMessageSendTrait for OrderCreatedEvent {}
// Define a consumer that processes Protobuf messages
struct OrderProcessor;
impl Processor<Message, Result<(), Error>> for OrderProcessor {
async fn process(&self, msg: Message) -> Result<(), Error> {
// Parse Protobuf message
let order = OrderData::parse_from_bytes(msg.payload)?;
// Process the order
println!("Processing order: {}", order.order_id);
Ok(())
}
}