I have a an enum which has a single tuple variant, short example:
#[derive(Serialize)]
enum Test {
A,
B(String),
}
I'd like Test::B to be serialized untagged, so only the String value it holds gets serialized - serializing Test::B("some string".to_owned()) will return "some string". Setting #[serde(untagged)] won't work as it makes Test::A serialize to null, I also tried using serialize_with on that variant, but realized that only gives access to the String field in that variant.
I'm wondering if anyone knows is it even possible to do this without resorting to writing a fully custom implementation of Serialize? I want to avoid that as the real enum has many other unit like variants (see octocrab/events.rs at master · XAMPPRocky/octocrab · GitHub).
This playground link should make it clearer Rust Playground.
Instead of writing a custom Serialize implementation, it is also possible to wrap the Serializer to get the desired results. I'm not sure if that is easier overall. Playground
These are the relevant lines:
Ah thanks! That makes sense, I didn't even think of that. The only downside is having all the unimplemented trait methods there. But it's not so bad.
I overlooked another solution too which I think I will go with. The main concern I had with implementing a custom Serializer was just repeating the enum variant names as strings constantly, error prone. I didn't event think of using a macro
So, I think something like this solves my main problem:
macro_rules! event_type {
( $( $name:ident ),+ $(,)? ) => {
/// The type of an event.
#[derive(Debug, Clone, PartialEq, Deserialize)]
#[non_exhaustive]
pub enum EventType {
$($name),+,
UnknownEvent(String),
}
impl Serialize for EventType {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self {
$(EventType::$name => serializer.serialize_str(stringify!($name))),+,
EventType::UnknownEvent(typ) => serializer.serialize_str(typ),
}
}
}
...
};
}
Turns out this also helps with repetition in other places too.