use serde::{Serialize, Serializer};
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub enum Patch<T> {
#[default]
Keep,
Null,
Set(T),
}
impl<T> Patch<T> {
pub fn is_keep(&self) -> bool {
matches!(self, Patch::Keep)
}
}
impl<T> From<T> for Patch<T> {
fn from(value: T) -> Self {
Patch::Set(value)
}
}
impl<T: Serialize> Serialize for Patch<T> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match self {
Patch::Keep | Patch::Null => serializer.serialize_none(),
Patch::Set(value) => value.serialize(serializer),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde::Serialize;
#[derive(Serialize)]
struct Body {
#[serde(skip_serializing_if = "Patch::is_keep")]
password: Patch<String>,
#[serde(skip_serializing_if = "Patch::is_keep")]
max_clicks: Patch<u32>,
#[serde(skip_serializing_if = "Patch::is_keep")]
alias: Patch<String>,
}
#[test]
fn wire_bytes_distinguish_all_three_states() {
let body = Body {
password: Patch::Null,
max_clicks: Patch::Set(10),
alias: Patch::Keep,
};
let json = serde_json::to_string(&body).unwrap();
assert_eq!(json, r#"{"password":null,"max_clicks":10}"#);
}
}