Invoer (.proto-schema)

Uitvoer (Rust)

Wat deze tool doet

Je hebt een Protocol Buffers-schema en een Rust-service of -client die ermee moet praten. De standaardroute is prost (of tonic voor gRPC) ingehaakt in een build.rs-script — solide, maar overkill als je gewoon de types wil schetsen en de vorm wil aftikken tegen je code. Deze converter maakt van het schema struct-definities, in je browser. Plakken, kopiëren, in src/types.rs droppen, doorgaan.

De uitvoer gebruikt #[derive(Debug, Default, Clone, Serialize, Deserialize)] op elke struct, zodat hij via serde netjes door JSON heen-en-weer gaat, en #[repr(i32)]-enums waarvan de zero-value-variant #[default] draagt, zodat Default::default() de proto3-semantiek volgt. Singuliere geneste messages worden Option<T> — Rust eist expliciete nullability, en dat past bij wat prost genereert. Vec<T> voor repeated-velden en HashMap<K, V> voor maps krijgen allebei #[serde(default)], zodat ontbrekende velden naar lege containers deserialiseren in plaats van te crashen.

De type-mapping volgt de proto3 JSON-mapping-spec: string/bytesString/Vec<u8>, de verschillende geformatteerde integers mappen naar i32/i64/u32/u64, en de floats landen op f32/f64. Veldnamen worden naar snake_case omgezet (al de Rust-conventie, dus de meeste velden gaan ongewijzigd door), en enum-varianten verliezen het schreeuwerige SCREAMING_SNAKE-prefix — ORDER_STATUS_UNSPECIFIED in enum OrderStatus wordt Unspecified, zoals je het met de hand zou schrijven. De conversie draait volledig client-side; niets uit je schema verlaat de pagina.

Hoe te gebruiken

Drie stappen. De uitvoer is direct te plakken in elke Rust-crate die serde in zijn dependencies heeft.

1

Plak je .proto-schema

Gooi het schema in de linker editor. syntax = "proto3"; bovenaan is optioneel — de parser kan om met geneste message-blokken, enum-declaraties, oneof, map<K, V> en veldopties. Imports worden herkend maar overgeslagen — plak geïmporteerde types dus inline als je erop steunt.

Veldnamen volgen automatisch de Rust-conventies: order_id blijft order_id, shippingAddress (als je camelCase in je schema hebt) wordt shipping_address. Struct- en enum-namen blijven PascalCase.

2

Lees de uitvoer

Aan de rechterkant: een platte lijst van pub struct- en pub enum-declaraties. Eerst de enums, dan de messages in de volgorde van declaratie, met geneste types vóór hun ouders. De regel use serde::{Deserialize, Serialize}; staat er altijd; use std::collections::HashMap; verschijnt alleen als je schema map-velden bevat.

3

Drop in je crate

Plak de uitvoer in een module-bestand. Zolang je serde = { version = "1", features = ["derive"] } en serde_json in je Cargo.toml hebt, compileert het. Daarna is het gewoon Rust — verbind het met een reqwest-client, een Cloudflare Worker, een axum-handler, overal waar je getypeerde toegang nodig hebt tot de message-data.

Wanneer dit echt tijd bespaart

Types schetsen voor een nieuwe Rust-service

Je bouwt een Rust-service die een gRPC-gateway-endpoint aanroept, maar je wil nog geen volledige build.rs met prost optuigen. Plak het .proto, drop de structs in types.rs, decodeer het antwoord als JSON, levert het prototype af.

Een Protobuf API-wijziging reviewen

Een backend-collega heeft velden aan een message toegevoegd. Je wil zien hoe de Rust-vorm verandert zonder de hele crate te herbouwen. Plak het nieuwe .proto, vergelijk de uitvoer met je bestaande types, laat een gerichte review-opmerking achter.

Door prost gegenereerde code naast leggen

Je build gebruikt prost met eigen type_attribute-regels en je wil een schone referentie van hoe de niet-gemodificeerde types eruitzien. Plak hier het schema voor een vergelijking naast elkaar. Handig wanneer je attribuutwijzigingen plant of naar een andere codegen-pipeline migreert.

CLI-tools en eenmalige scripts

Je schrijft een kleine Rust-CLI die een JSON-API aanroept die op Protobuf rust. prost optuigen voor een tool van 100 regels is meer ceremonie dan het werk vraagt. Pak hier de structs, derive serde, lever de binary af.

Veelgestelde vragen

Wordt mijn schema ergens naartoe gestuurd?

Nee. De parser én de Rust-emitter draaien beide als JavaScript in je browser. Open de DevTools, kijk naar de Network-tab terwijl je plakt — nul requests. Handig als je schema interne typenamen, package-paden of dingen bevat die je niet naar een derde partij wil sturen.

Waarom zitten geneste messages in een Option verpakt?

Rust heeft geen nullable referenties zoals Java of Go — of een waarde is aanwezig, of je gebruikt Option<T> om afwezigheid expliciet te maken. Singuliere submessages in proto3 zijn op de draad nullable (de field-tag kan helemaal ontbreken), dus de idiomatische Rust-vorm is Option<Address>, niet Address. Dit komt overeen met wat prost genereert. Scalars en enums worden niet ingepakt, omdat hun zero-waarden (lege string, 0, false, de #[default]-enum-variant) geldige Rust-waarden zijn.

Waarom zijn 64-bits ints getypeerd als i64/u64 in plaats van strings?

In Rust is er geen precisieprobleem — i64 en u64 zijn first-class types, anders dan in JavaScript waar 64-bits waarden strings worden. Als je JSON deserialiseert dat door een strikte proto3 JSON-encoder is gemaakt, komen de waarden als strings binnen; serde converteert niet automatisch. Voeg #[serde(with = "serde_with::DisplayFromStr")] of een eigen deserializer toe op die velden als je dat tegenkomt.

Waarom HashMap in plaats van BTreeMap?

HashMap komt overeen met wat prost voor map<K, V>-velden uitspuwt en is de juiste default — proto-map-velden zijn ongeordend. Als je een stabiele iteratievolgorde nodig hebt, verander het type met de hand naar BTreeMap; de rest van de code hoeft niet te veranderen.

Moet ik deze uitvoer met prost of tonic gebruiken?

Dit zijn pure serde-derived structs, geen door prost gecodeerde. Ze gaan via serde_json heen-en-weer door proto3 JSON, maar coderen/decoderen het binaire wire-format niet. Als je binaire protobuf-codering nodig hebt, draai prost via een build.rs-stap. Als je gRPC nodig hebt, gebruik tonic. Deze converter is voor het JSON-over-HTTP-geval (gRPC-gateway, Connect, JSON-transcoding).

Werkt het met oneof?

Elk veld van een oneof komt eruit als gewoon struct-veld. De uitvoer dwingt de "precies één"-beperking die oneof impliceert niet af — daarvoor zou je een Rust-enum nodig hebben met een variant per geval, wat afhangt van je runtime-semantiek. Heb je strikte oneof-afhandeling nodig, dan herwerk je de uitvoer met de hand naar een pub enum.

Gerelateerde tools

Als je met Protobuf, JSON en Rust werkt, passen deze goed bij elkaar: