serde-repr

Derive macros that serialize and deserialize C-like Rust enums as their underlying integer repr value instead of the variant name.

Library
Cargo
v0.1.21
271stars
MIT OR Apache-2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
51/100Fair
Development Activity52
Maintenance36
Community36
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
76/100Good
Architecture78
Code Quality82
Innovation55
Learning Curve90

serde_repr is a small, focused Rust proc-macro crate that provides two derive macros, Serialize_repr and Deserialize_repr, implementing Serde’s Serialize and Deserialize traits for C-like enums. Instead of encoding an enum variant by its string name (Serde’s default for unit-only enums), it encodes and decodes the variant as its underlying #[repr(…)] integer value — the same representation the enum already uses at the language level.

This is the standard solution in the Rust ecosystem when you need an enum to round-trip through JSON, TOML, or any Serde-compatible format as a plain number (e.g. matching a numeric status code or protocol field from an external API), rather than as a quoted string. The crate is maintained by David Tolnay, author of serde and syn, and is widely depended upon across the Rust package ecosystem.

What You Get

  • Serialize_repr derive macro — serializes any unit-variant enum as its repr integer discriminant
  • Deserialize_repr derive macro — deserializes a repr integer back into the matching enum variant, with a clear error listing valid values when no variant matches
  • #[serde(other)] support — designate one variant as a catch-all default for unrecognized integer values instead of erroring
  • Works with both explicit (Two = 2) and implicit (relying on Rust’s default 0, 1, 2… numbering) enum discriminants
  • Compile-time validation — rejects non-unit variants, generic enums, and enums missing a #[repr(…)] attribute with descriptive errors

Common Use Cases

  • Deserializing a numeric status/type code field from a third-party JSON API into a typed Rust enum
  • Serializing internal enum state to JSON/TOML/etc. as compact integers instead of verbose string tags
  • Modeling protocol or file-format constants (e.g. a wire protocol’s numeric opcode field) as a Rust enum
  • Providing a graceful fallback variant via #[serde(other)] when an API may emit values not yet known to the client

Under The Hood

Architecture The crate is a single proc-macro library (src/lib.rs) exposing two #[proc_macro_derive] entry points, Serialize_repr and Deserialize_repr, each parsing the incoming enum via a dedicated Input parser (src/parse.rs) built on syn’s DeriveInput. The parser walks the enum’s #[repr(…)] attribute to extract the underlying integer type, validates that every variant is a unit variant with no generics, and locates at most one #[serde(other)] default variant. Each derive macro then uses quote! to emit a trait impl: Serialize_repr matches each variant to its “as repr” cast and delegates to the repr type’s own Serialize; Deserialize_repr deserializes the repr integer first, then matches it against per-variant discriminant constants declared in a hidden zero-sized struct, falling through to the #[serde(other)] variant or a formatted error listing valid values. The design cleanly separates syntax parsing (parse.rs) from code generation (lib.rs), and nothing here executes at the caller’s runtime beyond the generated impls — changing the parsing logic only affects what enum shapes are accepted at compile time.

Tech Stack A Rust proc-macro crate (edition 2021, rust-version 1.71) built on the standard proc-macro toolchain: proc-macro2 and quote for token generation, and syn (major version 3) for parsing the derive input’s AST. Dev-dependencies include serde and serde_json for round-trip testing, trybuild for UI/compile-fail testing of macro error messages, and rustversion to gate version-specific test behavior. There is no runtime dependency beyond serde itself (required transitively by the generated impls) — the crate has no build step beyond cargo and ships as a proc-macro crate-type, so it compiles into the caller’s build as part of normal cargo derive expansion.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search