Rust Pattern: serde tags

March 15, 2026

(I’m going to try and post more “Rust learning moments” on here, feedback welcome on mastodon 😀)

Some protocols – including the Fowl frontend protocol – encode things as JSON, and include a "type" (or in my case "kind") attribute to tell you what sort of message this is.

For example:

{
    "kind": "set-code",
    "code": "999-foo-bar"
}

For a naive implementation in Rust, it’s nice to use an enum for this:

enum FowlCommand {
    SetCode(String),
}

Looking ahead just a little bit, maybe we want slightly more structure so that the names match up:

enum FowlCommand {
    AllocateCode {},
    SetCode { code: String },
}

As pointed out to me on ##rust on Libera, serde has a built-in way to deal with this, called an internally tagged enum. This means that we can add a few things to the above and get a fully working “JSON to Rust datastructure” working:

#[derive(Debug, Serialize)]
#[serde(tag = "kind")]
enum FowlCommand {
    #[serde(rename = "allocate-code")]
    AllocateCode {},
    #[serde(rename = "set-code")]
    SetCode { code: String },
}

This will then emit JSON like {"kind": "set-code", "code": "999-foo-bar"} to match the fowld front-end control protocol.

Neat!