Protozoa 🦠

A complete Protocol Buffers compiler and library for Gleam, providing full proto3 support with type-safe code generation, service definitions, and streaming RPC support.

Package VersionHex Docs

Features

✅ Complete proto3 support - Messages, enums, services, nested types, oneofs, maps, and repeated fields
✅ Service/RPC definitions - Full gRPC support with streaming (client, server, bidirectional)
✅ Import resolution - Handles import statements with configurable search paths
✅ Well-known types - Google's standard protobuf types (Timestamp, Duration, Any, etc.)
✅ Field options - Support for deprecated, json_name, packed, and custom options
✅ Type-safe codegen - Generates idiomatic Gleam code with proper type safety
✅ CLI tools - Easy-to-use command line interface with project integration
✅ All field types - Full support for all scalar types, including fixed32/fixed64
✅ Cross-file imports - Resolves dependencies between multiple proto files

Quick Start

Installation

Add to your gleam.toml:

[dependencies]
protozoa = ">= 1.0.0 and < 2.0.0"

Project Setup (Recommended)

  1. Create your proto files in src/[your-app]/proto/:
your-project/
├── gleam.toml
└── src/
    └── myapp/
        └── proto/
            ├── user.proto
            ├── message.proto
            └── user_service.proto
  1. Generate Gleam code with the convenient CLI:
# Generate all proto files in your project
gleam run -m protozoa

# Check if proto files need regeneration (useful for CI)
gleam run -m protozoa check
  1. Use the generated code in your Gleam modules:
import myapp/proto/user
import myapp/proto/message
import myapp/proto/user_service

pub fn example() {
  // Create and encode messages
  let user = user.User(name: "Alice", age: 30, active: True)
  let encoded = user.encode_user(user)
  
  // Decode messages
  let decoded = user.decode_user(encoded)
  
  // Use service stubs for gRPC clients
  let client = user_service.UserServiceClient(endpoint: "http://api.example.com")
}

Manual Usage

For custom workflows, you can also use protozoa directly:

# Compile a specific proto file
gleam run -m protozoa -- message.proto ./output

# Use custom import paths
gleam run -m protozoa -- -I./common -I./vendor message.proto ./src

# Check if files need regeneration (full CLI mode)
gleam run -m protozoa -- --check

CLI Reference

Automatic Project Integration

The recommended approach is to use gleam run -m protozoa, which automatically:

# Generate all proto files (recommended)
gleam run -m protozoa

# Check if proto files have changed
gleam run -m protozoa check

Manual Commands

For advanced usage or custom project structures:

# Single file compilation
gleam run -m protozoa -- input.proto output.gleam

# Multiple import paths
gleam run -m protozoa -- -I./proto -I./vendor input.proto output.gleam

# Directory processing
gleam run -m protozoa -- ./proto/ ./src/generated/

# Status checking
gleam run -m protozoa -- --check ./proto/

Supported Features

Protocol Buffer Features

Feature Support Description
Messages ✅ Complete Message definitions with all field types
Enums ✅ Complete Enum definitions with proper value handling
Services ✅ Complete gRPC service definitions with streaming support
Nested Types ✅ Complete Messages and enums nested within messages
Oneofs ✅ Complete Union types with proper variant handling
Maps ✅ Complete Map fields with Dict support
Repeated Fields ✅ Complete List/array fields with proper encoding
Import System ✅ Complete Cross-file dependencies and path resolution
Well-Known Types ✅ Complete Google's standard types auto-imported
Field Options ✅ Complete deprecated, json_name, packed options

RPC/Service Features

Streaming Type Syntax Support Generated Code
Unaryrpc Method(Request) returns (Response) ✅ Client/server stubs
Server Streamingrpc Method(Request) returns (stream Response) ✅ Streaming interface
Client Streamingrpc Method(stream Request) returns (Response) ✅ Streaming interface
Bidirectionalrpc Method(stream Request) returns (stream Response) ✅ Full duplex interface

Field Types

Proto Type Gleam Type Wire Type Support
boolBool Varint ✅
int32, sint32Int Varint ✅
int64, sint64Int Varint ✅
uint32, uint64Int Varint ✅
fixed32, sfixed32Int Fixed32 ✅
fixed64, sfixed64Int Fixed64 ✅
floatFloat Fixed32 ✅
doubleFloat Fixed64 ✅
stringString Length-delimited ✅
bytesBitArray Length-delimited ✅
Message types Custom types Length-delimited ✅
Enum types Custom types Varint ✅

Generated Code Examples

Messages with Field Options

syntax = "proto3";
package example;

message User {
  string name = 1;
  int32 age = 2 [deprecated = true];
  string email = 3 [json_name = "email_address"];
  repeated int32 scores = 4 [packed = true];
}

Generates:

pub type User {
  User(
    name: String,
    age: Int, // @deprecated: This field is deprecated
    email: String,
    scores: List(Int),
  )
}

pub fn encode_user(user: User) -> BitArray {
  // ... encoding implementation
}

pub fn user_decoder() -> decode.Decoder(User) {
  // ... decoding implementation
}

Services with Streaming

syntax = "proto3";
package example;

service UserService {
  rpc GetUser(GetUserRequest) returns (GetUserResponse);
  rpc StreamUsers(StreamRequest) returns (stream GetUserResponse);
  rpc UploadData(stream UploadRequest) returns (UploadResponse);
  rpc Chat(stream ChatMessage) returns (stream ChatMessage);
}

Generates:

/// Client interface for UserService service
pub type UserServiceClient {
  UserServiceClient(
    endpoint: String,
  )
}

/// Server interface for UserService service
pub type UserServiceServer {
  UserServiceServer(
    // Server implementation fields
  )
}

// Method signatures for client:
  // GetUser(GetUserRequest) -> GetUserResponse // Unary call
  // StreamUsers(StreamRequest) -> GetUserResponse // Server streaming
  // UploadData(UploadRequest) -> UploadResponse // Client streaming
  // Chat(ChatMessage) -> ChatMessage // Bidirectional streaming

Well-Known Types

syntax = "proto3";
package example;

import "google/protobuf/timestamp.proto";
import "google/protobuf/duration.proto";

message Event {
  string name = 1;
  google.protobuf.Timestamp created_at = 2;
  google.protobuf.Duration duration = 3;
}

Generates with automatic imports:

pub type Event {
  Event(
    name: String,
    created_at: Timestamp,
    duration: Duration,
  )
}

Development Status

Recently Completed ✅

High Priority Roadmap

Medium Priority

Low Priority

Technical Details

Contributing

Contributions are welcome! Please feel free to submit issues, feature requests, or pull requests.

License

This project is licensed under the MIT License.