1use core::ops::Deref;
7
8use serde::{Deserialize, Deserializer, Serialize, Serializer};
9
10#[derive(Debug, Clone, Default, Eq, PartialEq)]
20pub enum MsgraphField<T> {
21 #[default]
24 Unset,
25 Null,
28 Set(T),
30}
31
32impl<T> MsgraphField<T> {
33 pub fn is_unset(&self) -> bool {
35 matches!(self, Self::Unset)
36 }
37
38 pub fn as_option(&self) -> Option<&T> {
40 match self {
41 Self::Set(value) => Some(value),
42 _ => None,
43 }
44 }
45
46 pub fn into_option(self) -> Option<T> {
48 match self {
49 Self::Set(value) => Some(value),
50 _ => None,
51 }
52 }
53
54 pub fn set_or_null(value: Option<T>) -> Self {
59 match value {
60 Some(value) => Self::Set(value),
61 None => Self::Null,
62 }
63 }
64}
65
66impl<T: Deref> MsgraphField<T> {
67 pub fn as_deref(&self) -> Option<&T::Target> {
70 self.as_option().map(|value| value.deref())
71 }
72}
73
74impl<T> From<T> for MsgraphField<T> {
75 fn from(value: T) -> Self {
76 Self::Set(value)
77 }
78}
79
80impl<T: Serialize> Serialize for MsgraphField<T> {
81 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
82 match self {
83 Self::Unset | Self::Null => serializer.serialize_none(),
87 Self::Set(value) => value.serialize(serializer),
88 }
89 }
90}
91
92impl<'de, T: Deserialize<'de>> Deserialize<'de> for MsgraphField<T> {
93 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
94 match Option::<T>::deserialize(deserializer)? {
95 Some(value) => Ok(Self::Set(value)),
96 None => Ok(Self::Null),
97 }
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use alloc::{string::String, vec, vec::Vec};
104
105 use serde::{Deserialize, Serialize};
106 use serde_json::json;
107
108 use crate::v1::field::MsgraphField;
109
110 #[derive(Debug, Default, Deserialize, Serialize, Eq, PartialEq)]
111 struct Body {
112 #[serde(default, skip_serializing_if = "MsgraphField::is_unset")]
113 name: MsgraphField<String>,
114 #[serde(default, skip_serializing_if = "MsgraphField::is_unset")]
115 phones: MsgraphField<Vec<String>>,
116 }
117
118 #[test]
119 fn unset_fields_are_omitted() {
120 let body = serde_json::to_value(Body::default()).unwrap();
121 assert_eq!(body, json!({}));
122 }
123
124 #[test]
125 fn null_fields_serialize_as_explicit_null() {
126 let body = Body {
127 name: MsgraphField::Null,
128 phones: MsgraphField::Null,
129 };
130 assert_eq!(
131 serde_json::to_value(&body).unwrap(),
132 json!({ "name": null, "phones": null })
133 );
134 }
135
136 #[test]
137 fn set_fields_serialize_as_values_including_empty_collections() {
138 let body = Body {
139 name: MsgraphField::Set(String::from("Jane")),
140 phones: MsgraphField::Set(vec![]),
141 };
142 assert_eq!(
143 serde_json::to_value(&body).unwrap(),
144 json!({ "name": "Jane", "phones": [] })
145 );
146 }
147
148 #[test]
149 fn deserialization_distinguishes_missing_from_null() {
150 let body: Body = serde_json::from_value(json!({ "name": null })).unwrap();
151 assert_eq!(body.name, MsgraphField::Null);
152 assert_eq!(body.phones, MsgraphField::Unset);
153
154 let body: Body = serde_json::from_value(json!({ "phones": ["+33"] })).unwrap();
155 assert_eq!(body.name, MsgraphField::Unset);
156 assert_eq!(body.phones, MsgraphField::Set(vec![String::from("+33")]));
157 }
158}