Input (.proto-skema)

Output (Rust)

Hvad dette værktøj gør

Du har et Protocol Buffers-skema og en Rust-service eller -klient, der skal snakke med det. Standardvejen er prost (eller tonic til gRPC) hægtet ind i et build.rs-script — solidt, men overkill, når du bare vil skitsere typerne og tjekke formerne mod din kode. Denne konverter laver skemaet om til struct-definitioner i din browser. Indsæt, kopiér, smid i src/types.rs, kør videre.

Outputtet bruger #[derive(Debug, Default, Clone, Serialize, Deserialize)] på hver struct, så den round-tripper via JSON med serde, og #[repr(i32)]-enums hvor nul-værdivarianten er markeret #[default], så Default::default() matcher proto3-semantikken. Singulære nestede messages bliver til Option<T> — Rust kræver eksplicit nullability, og det matcher det, prost genererer. Vec<T> til repeated-felter og HashMap<K, V> til maps får begge #[serde(default)], så manglende felter deserialiseres til tomme containere i stedet for at fejle.

Type-mappingen følger proto3 JSON-mapping-specifikationen: string/bytesString/Vec<u8>, de forskellige størrelses-heltal mapper til i32/i64/u32/u64, og floats lander på f32/f64. Feltnavne konverteres til snake_case (det er allerede Rust-konventionen, så de fleste felter ryger igennem urørt), og enum-varianter mister det skrigende SCREAMING_SNAKE-præfiks — ORDER_STATUS_UNSPECIFIED i enumen OrderStatus bliver Unspecified, præcis som du ville skrive det i hånden. Konverteringen kører helt klient-side; intet fra dit skema forlader siden.

Sådan bruger du det

Tre trin. Outputtet er klar til at indsætte i enhver Rust-crate, der har serde i sine afhængigheder.

1

Indsæt dit .proto-skema

Smid skemaet i editoren til venstre. syntax = "proto3"; i toppen er valgfrit — parseren håndterer nestede message-blokke, enum-deklarationer, oneof, map<K, V> og feltoptions. Imports genkendes, men springes over, så indsæt importerede typer inline, hvis du afhænger af dem.

Feltnavne følger automatisk Rust-konventionerne: order_id bliver til order_id, shippingAddress (hvis du har camelCase i dit skema) bliver til shipping_address. Struct- og enum-navne forbliver i PascalCase.

2

Læs outputtet

Til højre: en flad liste af pub struct- og pub enum-deklarationer. Enums kommer først, derefter messages i deklarationsrækkefølge, med nestede typer før deres forældre. Linjen use serde::{Deserialize, Serialize}; er der altid; use std::collections::HashMap; dukker kun op, hvis dit skema har map-felter.

3

Smid det i din crate

Indsæt outputtet i en modulfil. Så længe du har serde = { version = "1", features = ["derive"] } og serde_json i din Cargo.toml, så kompilerer det. Derfra er det almindelig Rust — kobl det på en reqwest-klient, en Cloudflare Worker, en axum-handler, hvor end du har brug for typet adgang til messagedataen.

Hvornår det faktisk sparer tid

Skitsere typer til en ny Rust-service

Du bygger en Rust-service, der bruger en gRPC-gateway-endpoint, men du har ikke lyst til at sætte en fuld build.rs op med prost endnu. Indsæt .proto’en, smid structerne i types.rs, JSON-decode svaret, send prototypen ud.

Reviewe en Protobuf API-ændring

En backend-kollega har tilføjet felter til en message. Du vil se, hvordan Rust-formen ændrer sig uden at genbygge hele craten. Indsæt den nye .proto, diff outputtet mod dine eksisterende typer, læg en fokuseret review-kommentar.

Krydstjek mod prost-genereret kode

Dit build bruger prost med egne type_attribute-regler, og du vil have en ren reference på, hvordan de umodificerede typer ser ud. Indsæt skemaet her for en side-om-side. Brugbart, når du planlægger attributændringer eller migrerer til en anden codegen-pipeline.

CLI-værktøjer og engangsscripts

Du skriver en lille Rust-CLI, der kalder et JSON-API, som er drevet af Protobuf. At koble prost på alene for et 100-linjers værktøj er mere ceremoni, end opgaven kræver. Tag structerne herfra, derive serde, send binæren ud.

Almindelige spørgsmål

Bliver mit skema sendt nogen steder hen?

Nej. Parseren og Rust-emitteren kører begge som JavaScript i din browser. Åbn DevTools, hold øje med Network-fanen mens du indsætter — nul requests. Brugbart, når dit skema indeholder interne typenavne, pakkestier eller noget, du ikke ville sende til en tredjepartstjeneste.

Hvorfor er nestede messages pakket ind i Option?

Rust har ikke nullable referencer som Java eller Go — enten er en værdi til stede, eller også bruger du Option<T> for at gøre fraværet eksplicit. Singulære submessages i proto3 er nullable på ledningen (felt-taggen kan mangle helt), så den idiomatiske Rust-form er Option<Address>, ikke Address. Det matcher det, prost genererer. Skalarer og enums pakkes ikke ind, fordi deres nul-værdier (tom streng, 0, false, #[default]-enum-varianten) er gyldige Rust-værdier.

Hvorfor er 64-bit ints typed som i64/u64 i stedet for strings?

I Rust er der ingen præcisionsbekymring — i64 og u64 er førsteklassetyper, modsat JavaScript hvor 64-bit værdier er strings. Hvis du deserialiserer JSON produceret af en streng proto3 JSON-encoder, ankommer værdierne som strings; serde konverterer ikke automatisk. Læg #[serde(with = "serde_with::DisplayFromStr")] eller en egen deserializer på de felter, hvis du rammer det tilfælde.

Hvorfor HashMap i stedet for BTreeMap?

HashMap matcher det, prost udsender for map<K, V>-felter, og er den rette default — protos map-felter er uordnede. Hvis du har brug for stabil iterationsrækkefølge, så skift typen i hånden til BTreeMap; resten af koden behøver ikke ændres.

Skal jeg bruge dette output med prost eller tonic?

Det er almindelige serde-derived structs, ikke prost-encoded. De round-tripper via proto3 JSON med serde_json, men de encoder/decoder ikke det binære wire-format. Hvis du har brug for binær protobuf-encoding, kør prost via et build.rs-trin. Hvis du har brug for gRPC, brug tonic. Denne konverter er til JSON-over-HTTP-tilfældet (gRPC-gateway, Connect, JSON-transcoding).

Håndterer den oneof?

Hvert felt i en oneof udsendes som et almindeligt struct-felt. Outputtet håndhæver ikke "præcis ét"-betingelsen, som oneof implicerer — til det skulle du bruge en Rust-enum med en variant pr. case, hvilket afhænger af din runtime-semantik. Hvis du har brug for streng oneof-håndtering, så omredigér outputtet i hånden til en pub enum.

Relaterede værktøjer

Hvis du sysler med Protobuf, JSON og Rust, så passer disse godt sammen: