Expand description
Code generation for roam RPC bindings across multiple languages.
§This Is Where Code Generation Actually Happens
While roam-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 = roam_codegen::targets::typescript::generate(&detail);
std::fs::write("generated/calculator.ts", ts_code).unwrap();
// Generate Go server
let go_code = roam_codegen::targets::go::generate(&detail);
std::fs::write("generated/calculator.go", go_code).unwrap();
}§The Pipeline
#[service] trait → ServiceDescriptor → roam-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 roam::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 roam'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 insideThis is why validation happens here:
- Is this actually roam’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
Modules§
- code_
writer - Code writer with automatic indentation tracking for code generation.
- targets
Macros§
- cw_
write - Write formatted text to a CodeWriter (like std::write!)
- cw_
writeln - Write formatted text with newline to a CodeWriter (like std::writeln!)