1use serde::{Deserialize, Deserializer, Serialize, Serializer};
9
10use std::{fmt, hash, ops::Deref};
11
12#[derive(Debug, Clone, PartialEq, Eq, Hash)]
75pub struct Forgettable<T>(Option<T>);
76
77impl<T> Default for Forgettable<T> {
78 fn default() -> Self {
80 Forgettable(None)
81 }
82}
83
84impl<T> From<T> for Forgettable<T> {
85 fn from(value: T) -> Self {
86 Forgettable(Some(value))
87 }
88}
89
90impl<T> Forgettable<T> {
91 pub fn new(value: T) -> Self {
93 Forgettable(Some(value))
94 }
95
96 pub fn forgotten() -> Self {
98 Forgettable(None)
99 }
100
101 pub fn value(&self) -> Option<ForgettableRef<'_, T>> {
106 self.0.as_ref().map(ForgettableRef)
107 }
108
109 pub fn is_set(&self) -> bool {
111 self.0.is_some()
112 }
113
114 pub fn is_forgotten(&self) -> bool {
116 self.0.is_none()
117 }
118}
119
120impl<T: Serialize> Forgettable<T> {
121 #[doc(hidden)]
124 pub fn __extract_payload_value(&self) -> Option<serde_json::Value> {
125 self.0
126 .as_ref()
127 .map(|v| serde_json::to_value(v).expect("Failed to serialize forgettable field"))
128 }
129}
130
131impl<T: Serialize> Serialize for Forgettable<T> {
132 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
133 serializer.serialize_none()
134 }
135}
136
137impl<'de, T: Deserialize<'de>> Deserialize<'de> for Forgettable<T> {
138 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
139 let value = Option::<T>::deserialize(deserializer)?;
140 match value {
141 Some(v) => Ok(Forgettable(Some(v))),
142 None => Ok(Forgettable(None)),
143 }
144 }
145}
146
147#[cfg(feature = "json-schema")]
148impl<T: schemars::JsonSchema> schemars::JsonSchema for Forgettable<T> {
149 fn inline_schema() -> bool {
150 Option::<T>::inline_schema()
151 }
152
153 fn schema_name() -> std::borrow::Cow<'static, str> {
154 Option::<T>::schema_name()
155 }
156
157 fn schema_id() -> std::borrow::Cow<'static, str> {
158 Option::<T>::schema_id()
159 }
160
161 fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
162 Option::<T>::json_schema(generator)
163 }
164}
165
166pub struct ForgettableRef<'a, T>(&'a T);
172
173impl<T: fmt::Debug> fmt::Debug for ForgettableRef<'_, T> {
174 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
175 self.0.fmt(f)
176 }
177}
178
179impl<T: fmt::Display> fmt::Display for ForgettableRef<'_, T> {
180 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181 self.0.fmt(f)
182 }
183}
184
185impl<T> Deref for ForgettableRef<'_, T> {
186 type Target = T;
187
188 fn deref(&self) -> &T {
189 self.0
190 }
191}
192
193impl<T: PartialEq> PartialEq<T> for ForgettableRef<'_, T> {
194 fn eq(&self, other: &T) -> bool {
195 self.0 == other
196 }
197}
198
199impl<T: PartialEq> PartialEq for ForgettableRef<'_, T> {
200 fn eq(&self, other: &Self) -> bool {
201 self.0 == other.0
202 }
203}
204
205impl<T: Eq> Eq for ForgettableRef<'_, T> {}
206
207impl<T: hash::Hash> hash::Hash for ForgettableRef<'_, T> {
208 fn hash<H: hash::Hasher>(&self, state: &mut H) {
209 self.0.hash(state);
210 }
211}
212
213#[doc(hidden)]
218pub fn inject_forgettable_payload(event_json: &mut serde_json::Value, payload: serde_json::Value) {
219 if let (Some(event_obj), serde_json::Value::Object(payload_obj)) =
220 (event_json.as_object_mut(), payload)
221 {
222 for (key, value) in payload_obj {
223 event_obj.insert(key, value);
224 }
225 }
226}
227
228#[cfg(test)]
229mod tests {
230 use super::*;
231
232 #[test]
233 fn serialize_set_emits_null() {
234 let value: Forgettable<String> = Forgettable::new("Alice".to_string());
235 let json = serde_json::to_value(&value).unwrap();
236 assert_eq!(json, serde_json::json!(null));
237 }
238
239 #[test]
240 fn serialize_forgotten_emits_null() {
241 let value: Forgettable<String> = Forgettable::forgotten();
242 let json = serde_json::to_value(&value).unwrap();
243 assert_eq!(json, serde_json::json!(null));
244 }
245
246 #[test]
247 fn deserialize_value() {
248 let json = serde_json::json!("Alice");
249 let value: Forgettable<String> = serde_json::from_value(json).unwrap();
250 assert_eq!(value, Forgettable::new("Alice".to_string()));
251 }
252
253 #[test]
254 fn deserialize_null() {
255 let json = serde_json::json!(null);
256 let value: Forgettable<String> = serde_json::from_value(json).unwrap();
257 assert_eq!(value, Forgettable::forgotten());
258 }
259
260 #[test]
261 fn serialize_struct_with_forgettable_emits_null() {
262 #[derive(Serialize, Deserialize, Debug, PartialEq)]
263 struct Event {
264 #[serde(rename = "type")]
265 kind: String,
266 name: Forgettable<String>,
267 email: String,
268 }
269
270 let event = Event {
271 kind: "initialized".to_string(),
272 name: Forgettable::new("Alice".to_string()),
273 email: "alice@test.com".to_string(),
274 };
275 let json = serde_json::to_value(&event).unwrap();
276 assert_eq!(json["name"], serde_json::json!(null));
278 assert_eq!(json["email"], serde_json::json!("alice@test.com"));
279
280 let deserialized: Event = serde_json::from_value(json).unwrap();
282 assert_eq!(deserialized.name, Forgettable::forgotten());
283
284 let event_forgotten = Event {
286 kind: "initialized".to_string(),
287 name: Forgettable::forgotten(),
288 email: "alice@test.com".to_string(),
289 };
290 let json = serde_json::to_value(&event_forgotten).unwrap();
291 assert_eq!(json["name"], serde_json::json!(null));
292
293 let deserialized: Event = serde_json::from_value(json).unwrap();
294 assert_eq!(deserialized, event_forgotten);
295 }
296
297 #[test]
298 fn inject_payload() {
299 let mut json = serde_json::json!({
300 "type": "initialized",
301 "id": "uuid",
302 "name": null,
303 "email": "alice@test.com"
304 });
305
306 let payload = serde_json::json!({"name": "Alice"});
307 inject_forgettable_payload(&mut json, payload);
308
309 assert_eq!(json["name"], serde_json::json!("Alice"));
310 assert_eq!(json["email"], serde_json::json!("alice@test.com"));
311 }
312
313 #[test]
314 fn value_helpers() {
315 let set: Forgettable<String> = Forgettable::new("test".to_string());
316 assert!(set.is_set());
317 assert!(!set.is_forgotten());
318 assert_eq!(&*set.value().unwrap(), "test");
319
320 let forgotten: Forgettable<String> = Forgettable::forgotten();
321 assert!(!forgotten.is_set());
322 assert!(forgotten.is_forgotten());
323 assert!(forgotten.value().is_none());
324 }
325
326 #[test]
327 fn extract_payload_value() {
328 let set: Forgettable<String> = Forgettable::new("Alice".to_string());
329 assert_eq!(
330 set.__extract_payload_value(),
331 Some(serde_json::json!("Alice"))
332 );
333
334 let forgotten: Forgettable<String> = Forgettable::forgotten();
335 assert_eq!(forgotten.__extract_payload_value(), None);
336 }
337
338 #[test]
339 fn forgettable_ref_deref() {
340 let f = Forgettable::new("hello".to_string());
341 let r = f.value().unwrap();
342 assert_eq!(r.len(), 5);
344 assert_eq!(&*r, "hello");
345 }
346
347 #[test]
348 fn forgettable_ref_display() {
349 let f = Forgettable::new("Alice".to_string());
350 let r = f.value().unwrap();
351 assert_eq!(format!("{r}"), "Alice");
352 }
353
354 #[test]
355 fn forgettable_ref_partial_eq() {
356 let f = Forgettable::new("Alice".to_string());
357 let r = f.value().unwrap();
358 assert_eq!(r, "Alice".to_string());
359 }
360
361 #[test]
362 fn default_is_forgotten() {
363 let f: Forgettable<String> = Default::default();
364 assert!(f.is_forgotten());
365 assert!(f.value().is_none());
366 }
367
368 #[test]
369 fn from_value() {
370 let f: Forgettable<String> = "Alice".to_string().into();
371 assert!(f.is_set());
372 assert_eq!(&*f.value().unwrap(), "Alice");
373 }
374}