#serde #implicit #untagged #serialization #sender

serde-implicit

the serde(untagged) you wish you had

2 releases

Uses new Rust 2024

new 0.1.1 May 24, 2025
0.1.0 May 19, 2025

#754 in Encoding

Download history 88/week @ 2025-05-14

88 downloads per month

MIT license

11KB
126 lines

serde-implicit

the untagged enums you wish you had

When building api types in Rust it is common to see serde's untagged enum representation get used to provide a more 'ergonomic' or 'aesthetic' API surface.

#[derive(Deserialize, Serialize)]
#[serde(untagged)]
enum Message {
	// { "content": "i love serializing", "sender": "xldenis", "timestamp": 123 }
    Text { content: String, sender: String, timestamp: u64, },
	// { "image_url": "https://blah.com/omg.gif" }
    Image { image_url: String, caption: Option<String>, },
	// { "emoji": "floating_man", "message_id": 123 }
    Reaction { emoji: String, message_id: u64, },
}

This approach has one major downside: absolutely garbage error messages. Even when your enum types have completely disjoint fields, serde will blindly attempt to parse all variants. A single missing or extra field leads to the dreaded:

{ "content": "oops i mislabeled my field", "username": "xldenis", "timestamp": 1234 }

"data did not match any variant of untagged enum Message"

serde-implicit solves this problem by introducing an implicitly tagged enum representation. Each variant can be have a field annotated with #[serde(tag)], and when that field is seen in input we can "commit" to parsing that variant, producing better error messages as a side-effect.

{ "content": "oops i mislabeled my field", "username": "xldenis", "timestamp": 1234 }

"missing field `sender`"

Dependencies

~0.3–0.8MB
~19K SLoC