8 releases (4 breaking)
Uses new Rust 2024
| new 0.5.0 | May 15, 2026 |
|---|---|
| 0.4.0 | Apr 15, 2026 |
| 0.3.1 | Mar 30, 2026 |
| 0.2.2 | Mar 28, 2026 |
| 0.0.0 | Mar 23, 2026 |
#118 in #rpc
620KB
14K
SLoC
Code generation for vox RPC bindings across multiple languages.
This Is Where Code Generation Actually Happens
While vox-macros parses your service traits and emits metadata, this crate
consumes that metadata and generates actual protocol implementations for:
- TypeScript — Browser and Node.js clients
- Swift — iOS/macOS clients
- Go — Server and client implementations
- Java — Android and server implementations
- Python — Client bindings
- Rust — Extended codegen beyond what the proc macro provides
Usage: In Your build.rs
// In your service crate's build.rs
use my_service::calculator_service_detail;
fn main() {
let detail = calculator_service_detail();
// Generate TypeScript client
let ts_code = vox_codegen::targets::typescript::generate(&detail);
std::fs::write("generated/calculator.ts", ts_code).unwrap();
// Generate Go server
let go_code = vox_codegen::targets::go::generate(&detail);
std::fs::write("generated/calculator.go", go_code).unwrap();
}
The Pipeline
#[service] trait → ServiceDescriptor → vox-codegen → .ts, .go, .swift, ...
(your code) (runtime metadata) (build script) (generated code)
Why Build Scripts? (The Technical Reason)
Code generation happens in build scripts (not proc macros) because proc macros cannot see into the type system.
When a proc macro sees Tx<String> in a method signature, it sees tokens — it has
no idea if Tx refers to vox::channel::Tx or some user-defined type. It cannot
resolve type aliases, follow generic parameters, or inspect nested types.
But here, with facet::Shape, we have full type introspection:
// We can identify vox's Tx vs user-defined types
let shape = <Tx<String> as facet::Facet>::SHAPE;
// We can traverse nested types like Result<Vec<Tx<T>>, Error>
// and find the Tx buried inside
This is why validation happens here:
- Is this actually vox's
Tx/Rxchannel type? - Are channel types incorrectly used in error positions?
- What serialization does this nested type require?
Additional benefits of build scripts:
- File I/O — Build scripts can write files; proc macros cannot
- Configuration — Build scripts can read config files, env vars, etc.
- Flexibility — Different projects can generate different subsets of bindings
vox-codegen
Language binding generator for Vox service descriptors.
Role in the Vox stack
vox-codegen bridges Rust-defined schemas to non-Rust clients/servers above the RPC surface.
What this crate provides
- TypeScript and Swift code generation targets
- Rendering of service descriptors into client/server scaffolding
Fits with
voxservice definitions and generated descriptorsvox-hashandvox-typesfor shared protocol identity and type model
Part of the Vox workspace: https://github.com/bearcove/vox
Dependencies
~9–12MB
~229K SLoC