#[must_use]
pub fn flatten_tag(value: serde_json::Value, tag: &str) -> serde_json::Value {
let serde_json::Value::Object(outer) = value else {
return value;
};
let mut entries = outer.into_iter();
let (Some((name, payload)), None) = (entries.next(), entries.next()) else {
return serde_json::Value::Object(entries.collect());
};
let mut flat = serde_json::Map::new();
flat.insert(tag.to_string(), serde_json::Value::String(name));
match payload {
serde_json::Value::Object(fields) => flat.extend(fields),
serde_json::Value::Null => {}
other => {
flat.insert("value".to_string(), other);
}
}
serde_json::Value::Object(flat)
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn a_struct_variant_flattens_into_the_tag() {
assert_eq!(
flatten_tag(json!({"window_focused": {"window_id": 4}}), "event"),
json!({"event": "window_focused", "window_id": 4})
);
}
#[test]
fn a_unit_variant_is_just_its_tag() {
assert_eq!(flatten_tag(json!("applied"), "outcome"), json!("applied"));
assert_eq!(
flatten_tag(json!({"applied": null}), "outcome"),
json!({"outcome": "applied"})
);
}
#[test]
fn an_unnamed_payload_keeps_a_name() {
assert_eq!(
flatten_tag(json!({"conflict": 7}), "outcome"),
json!({"outcome": "conflict", "value": 7})
);
}
}