Protobuf till Rust-konverterare
Klistra in ett .proto-schema. Få Rust-structar och enums med serde-derives, snake_case-fält och Option<T> på nullbara submessages — redo att släppas in i din crate.
Indata (.proto-schema)
Utdata (Rust)
Vad det här verktyget gör
Du har ett Protocol Buffers-schema och en Rust-tjänst eller -klient som behöver prata med det. Standardvägen är prost (eller tonic för gRPC) inkopplat i ett build.rs-skript — solitt, men overkill när du bara vill skissa upp typerna och stämma av formerna mot din kod. Den här konverteraren gör om schemat till struct-definitioner i din webbläsare. Klistra in, kopiera, släpp in i src/types.rs, fortsätt jobba.
Utdatan använder #[derive(Debug, Default, Clone, Serialize, Deserialize)] på varje struct så att den åker round-trip via JSON med serde, och #[repr(i32)]-enums där noll-värdesvarianten är märkt med #[default] så att Default::default() matchar proto3-semantiken. Singulära nästade messages blir Option<T> — Rust kräver explicit nullbarhet och det matchar vad prost genererar. Vec<T> för repeated-fält och HashMap<K, V> för maps får båda #[serde(default)], så att fält som saknas deserialiseras till tomma containrar i stället för att smälla.
Typmappningen följer proto3 JSON-mappningsspecen: string/bytes → String/Vec<u8>, de olika storleksanpassade heltalen mappar till i32/i64/u32/u64, och flyttalen landar på f32/f64. Fältnamn konverteras till snake_case (det är redan Rust-konventionen, så de flesta fält åker igenom orörda), och enum-varianter tappar det skrikiga SCREAMING_SNAKE-prefixet — ORDER_STATUS_UNSPECIFIED i enumen OrderStatus blir Unspecified, precis som du skulle skriva det för hand. Konverteringen körs helt klientsidan; inget från ditt schema lämnar sidan.
Så använder du det
Tre steg. Utdatan är klar att klistra in i vilken Rust-crate som helst som har serde i sina beroenden.
Klistra in ditt .proto-schema
Släpp schemat i den vänstra editorn. syntax = "proto3"; överst är frivilligt — parsern hanterar nästade message-block, enum-deklarationer, oneof, map<K, V> och fältoptions. Imports känns igen men hoppas över, så klistra in importerade typer inline om du beror på dem.
Fältnamn följer Rusts konventioner automatiskt: order_id blir kvar som order_id, shippingAddress (om du har camelCase i ditt schema) blir shipping_address. Struct- och enum-namn behåller PascalCase.
Läs utdatan
Till höger: en platt lista med pub struct- och pub enum-deklarationer. Enums först, sedan messages i deklarationsordning, med nästade typer före sina föräldrar. Raden use serde::{Deserialize, Serialize}; finns alltid; use std::collections::HashMap; dyker bara upp om ditt schema har map-fält.
Släpp in i din crate
Klistra in utdatan i en modulfil. Så länge du har serde = { version = "1", features = ["derive"] } och serde_json i din Cargo.toml kompilerar det. Därefter är det vanlig Rust — koppla in det mot en reqwest-klient, en Cloudflare Worker, en axum-handler, vart du nu behöver typad åtkomst till messagedatan.
När det faktiskt sparar tid
Skissa typer för en ny Rust-tjänst
Du bygger en Rust-tjänst som konsumerar en gRPC-gateway-endpoint, men du vill inte sätta upp en full build.rs med prost än. Klistra in .proto:n, släpp structarna i types.rs, JSON-decoda svaret, skicka iväg prototypen.
Granska en Protobuf API-ändring
En backend-kollega har lagt till fält i ett message. Du vill se hur Rust-formen ändras utan att bygga om hela craten. Klistra in det nya .proto:t, diffa utdatan mot dina befintliga typer, lämna en fokuserad reviewkommentar.
Stämma av mot prost-genererad kod
Din build använder prost med egna type_attribute-regler och du vill ha en ren referens på hur de omodifierade typerna ser ut. Klistra in schemat här för en sida-vid-sida. Användbart när du planerar attributändringar eller migrerar till en annan codegen-pipeline.
CLI-verktyg och engångsskript
Du skriver en liten Rust-CLI som anropar ett JSON-API som backas av Protobuf. Att koppla in prost bara för ett 100-raders verktyg är mer ceremoni än uppdraget kräver. Plocka structarna härifrån, deriva serde, skicka iväg binären.
Vanliga frågor
Skickas mitt schema någonstans?
Nej. Både parsern och Rust-emittern kör som JavaScript i din webbläsare. Öppna DevTools, kolla Network-fliken medan du klistrar in — noll requests. Användbart när schemat innehåller interna typnamn, paket-paths eller annat du inte vill skicka till en tredjepartstjänst.
Varför är nästade messages inslagna i Option?
Rust har inga nullbara referenser som Java eller Go — antingen finns värdet, eller så använder du Option<T> för att göra frånvaron explicit. Singulära submessages i proto3 är nullbara på tråden (fältets tag kan saknas helt), så den idiomatiska Rust-formen är Option<Address>, inte Address. Det matchar vad prost genererar. Skalärer och enums slås inte in eftersom deras nollvärden (tom sträng, 0, false, #[default]-enumvarianten) är giltiga Rust-värden.
Varför är 64-bitars heltal typade som i64/u64 i stället för strängar?
I Rust finns ingen precisionsoro — i64 och u64 är förstaklassstyper, till skillnad från JavaScript där 64-bitars värden är strängar. Om du deserialiserar JSON producerad av en strikt proto3 JSON-encoder kommer värdena in som strängar; serde konverterar inte automatiskt. Lägg #[serde(with = "serde_with::DisplayFromStr")] eller en egen deserializer på de fälten om du hamnar i det läget.
Varför HashMap i stället för BTreeMap?
HashMap matchar vad prost emiterar för map<K, V>-fält och är rätt default — protos map-fält är oordnade. Behöver du stabil iterationsordning, byt typen för hand till BTreeMap; resten av koden behöver inte ändras.
Ska jag använda denna utdata med prost eller tonic?
Det här är vanliga serde-deriverade structar, inte prost-encodade. De åker round-trip via proto3 JSON med serde_json, men de encodar/decodar inte det binära wire-formatet. Behöver du binär protobuf-encoding, kör prost via ett build.rs-steg. Behöver du gRPC, använd tonic. Den här konverteraren är till för JSON-over-HTTP-fallet (gRPC-gateway, Connect, JSON-transcoding).
Hanterar den oneof?
Varje fält i en oneof emiteras som ett vanligt struct-fält. Utdatan tvingar inte fram "exakt en"-villkoret som oneof implicerar — för det skulle du behöva ett Rust-enum med en variant per fall, vilket beror på din runtime-semantik. Behöver du strikt oneof-hantering, redigera utdatan för hand till en pub enum.
Relaterade verktyg
Om du jobbar med Protobuf, JSON och Rust passar dessa bra ihop: