Skip to main content

json_serde/
lib.rs

1// Copyright 2026 Oxide Computer Company
2
3#![doc = include_str!("../README.md")]
4#![forbid(unsafe_code)]
5#![warn(missing_docs, missing_debug_implementations)]
6
7// Alias the crate under its external name so the unit tests can use the
8// documented attribute recipes verbatim.
9#[cfg(test)]
10extern crate self as json_serde;
11
12use serde_core::{
13    Deserialize, Deserializer, Serializer,
14    de::Error,
15    ser::{Impossible, SerializeSeq},
16};
17
18/// Deserializer function that always produces `Some(T)` if a value is present.
19///
20/// It is useful when one wants to distinguish between a field that's absent
21/// and a field that's present with a `null` value. For example, the annotation
22/// below may be used for a field that may be absent, but may not be `null`.
23///
24/// ```
25/// # #[derive(serde::Deserialize, serde::Serialize)]
26/// # struct Data {
27///     #[serde(
28///         default,
29///         deserialize_with = "::json_serde::deserialize_some",
30///         skip_serializing_if = "Option::is_none",
31///     )]
32///     field: Option<String>,
33/// # }
34/// ```
35///
36/// It can also be used with a "double-Option" to determine whether a field
37/// was absent, `null`, or had a value:
38/// ```
39/// # #[derive(serde::Deserialize, serde::Serialize)]
40/// # struct Data {
41///     #[serde(
42///         default,
43///         deserialize_with = "::json_serde::deserialize_some",
44///         skip_serializing_if = "Option::is_none",
45///     )]
46///     field: Option<Option<String>>,
47/// # }
48/// ```
49///
50/// In the first case, a `null` value results in an error because a `String`
51/// cannot be deserialized from `null`. In the second case, a `null` value
52/// results in `field` having a value of `Some(None)` since `Option<String>`
53/// *can* be deserialized from `null`.
54pub fn deserialize_some<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
55where
56    D: Deserializer<'de>,
57    T: Deserialize<'de>,
58{
59    T::deserialize(deserializer).map(Some)
60}
61
62/// Serializer used to flatten sequences into other sequences.
63///
64/// Wrap an in-progress [`SerializeSeq`] and serialize a sequence-shaped
65/// value into the wrapper: the value's elements are appended to the
66/// enclosing sequence. Values that do not serialize as a sequence are an
67/// error. Ending the flattened sequence leaves the enclosing serializer
68/// open for further elements.
69///
70/// The value must serialize as a serde *seq* (e.g. `Vec<T>`); fixed-size
71/// tuples and arrays serialize via `serialize_tuple` and are rejected.
72pub struct FlattenedSequenceSerializer<'a, S>(&'a mut S);
73
74impl<'a, S> FlattenedSequenceSerializer<'a, S>
75where
76    S: serde_core::ser::SerializeSeq,
77{
78    /// Wrap the in-progress sequence serializer `seq_serializer`.
79    pub fn new(seq_serializer: &'a mut S) -> Self {
80        Self(seq_serializer)
81    }
82
83    fn wrong_type_error<T>(kind: &str) -> Result<T, S::Error> {
84        Err(serde_core::ser::Error::custom(format!(
85            "FlattenedSequenceSerializer only supports sequence values, \
86             not {kind}",
87        )))
88    }
89}
90
91impl<S> std::fmt::Debug for FlattenedSequenceSerializer<'_, S> {
92    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93        f.debug_struct("FlattenedSequenceSerializer")
94            .finish_non_exhaustive()
95    }
96}
97
98impl<S> Serializer for FlattenedSequenceSerializer<'_, S>
99where
100    S: serde_core::ser::SerializeSeq,
101{
102    type Ok = ();
103    type Error = S::Error;
104
105    type SerializeSeq = Self;
106    type SerializeTuple = Impossible<Self::Ok, Self::Error>;
107    type SerializeTupleStruct = Impossible<Self::Ok, Self::Error>;
108    type SerializeTupleVariant = Impossible<Self::Ok, Self::Error>;
109    type SerializeMap = Impossible<Self::Ok, Self::Error>;
110    type SerializeStruct = Impossible<Self::Ok, Self::Error>;
111    type SerializeStructVariant = Impossible<Self::Ok, Self::Error>;
112
113    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
114        Ok(self)
115    }
116
117    fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
118        Self::wrong_type_error("tuple")
119    }
120
121    fn serialize_tuple_struct(
122        self,
123        _name: &'static str,
124        _len: usize,
125    ) -> Result<Self::SerializeTupleStruct, Self::Error> {
126        Self::wrong_type_error("tuple struct")
127    }
128
129    fn serialize_tuple_variant(
130        self,
131        _name: &'static str,
132        _variant_index: u32,
133        _variant: &'static str,
134        _len: usize,
135    ) -> Result<Self::SerializeTupleVariant, Self::Error> {
136        Self::wrong_type_error("tuple variant")
137    }
138
139    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
140        Self::wrong_type_error("map")
141    }
142
143    fn serialize_struct(
144        self,
145        _name: &'static str,
146        _len: usize,
147    ) -> Result<Self::SerializeStruct, Self::Error> {
148        Self::wrong_type_error("struct")
149    }
150
151    fn serialize_struct_variant(
152        self,
153        _name: &'static str,
154        _variant_index: u32,
155        _variant: &'static str,
156        _len: usize,
157    ) -> Result<Self::SerializeStructVariant, Self::Error> {
158        Self::wrong_type_error("struct variant")
159    }
160
161    fn serialize_bool(self, _v: bool) -> Result<Self::Ok, Self::Error> {
162        Self::wrong_type_error("bool")
163    }
164
165    fn serialize_i8(self, _v: i8) -> Result<Self::Ok, Self::Error> {
166        Self::wrong_type_error("i8")
167    }
168
169    fn serialize_i16(self, _v: i16) -> Result<Self::Ok, Self::Error> {
170        Self::wrong_type_error("i16")
171    }
172
173    fn serialize_i32(self, _v: i32) -> Result<Self::Ok, Self::Error> {
174        Self::wrong_type_error("i32")
175    }
176
177    fn serialize_i64(self, _v: i64) -> Result<Self::Ok, Self::Error> {
178        Self::wrong_type_error("i64")
179    }
180
181    fn serialize_u8(self, _v: u8) -> Result<Self::Ok, Self::Error> {
182        Self::wrong_type_error("u8")
183    }
184
185    fn serialize_u16(self, _v: u16) -> Result<Self::Ok, Self::Error> {
186        Self::wrong_type_error("u16")
187    }
188
189    fn serialize_u32(self, _v: u32) -> Result<Self::Ok, Self::Error> {
190        Self::wrong_type_error("u32")
191    }
192
193    fn serialize_u64(self, _v: u64) -> Result<Self::Ok, Self::Error> {
194        Self::wrong_type_error("u64")
195    }
196
197    fn serialize_f32(self, _v: f32) -> Result<Self::Ok, Self::Error> {
198        Self::wrong_type_error("f32")
199    }
200
201    fn serialize_f64(self, _v: f64) -> Result<Self::Ok, Self::Error> {
202        Self::wrong_type_error("f64")
203    }
204
205    fn serialize_char(self, _v: char) -> Result<Self::Ok, Self::Error> {
206        Self::wrong_type_error("char")
207    }
208
209    fn serialize_str(self, _v: &str) -> Result<Self::Ok, Self::Error> {
210        Self::wrong_type_error("str")
211    }
212
213    fn serialize_bytes(self, _v: &[u8]) -> Result<Self::Ok, Self::Error> {
214        Self::wrong_type_error("bytes")
215    }
216
217    fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
218        Self::wrong_type_error("None")
219    }
220
221    fn serialize_some<T>(self, _value: &T) -> Result<Self::Ok, Self::Error>
222    where
223        T: ?Sized + serde_core::Serialize,
224    {
225        Self::wrong_type_error("Some")
226    }
227
228    fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
229        Self::wrong_type_error("unit")
230    }
231
232    fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
233        Self::wrong_type_error("unit struct")
234    }
235
236    fn serialize_unit_variant(
237        self,
238        _name: &'static str,
239        _variant_index: u32,
240        _variant: &'static str,
241    ) -> Result<Self::Ok, Self::Error> {
242        Self::wrong_type_error("unit variant")
243    }
244
245    fn serialize_newtype_struct<T>(
246        self,
247        _name: &'static str,
248        _value: &T,
249    ) -> Result<Self::Ok, Self::Error>
250    where
251        T: ?Sized + serde_core::Serialize,
252    {
253        Self::wrong_type_error("newtype struct")
254    }
255
256    fn serialize_newtype_variant<T>(
257        self,
258        _name: &'static str,
259        _variant_index: u32,
260        _variant: &'static str,
261        _value: &T,
262    ) -> Result<Self::Ok, Self::Error>
263    where
264        T: ?Sized + serde_core::Serialize,
265    {
266        Self::wrong_type_error("newtype variant")
267    }
268}
269
270impl<S> SerializeSeq for FlattenedSequenceSerializer<'_, S>
271where
272    S: serde_core::ser::SerializeSeq,
273{
274    type Ok = ();
275
276    type Error = S::Error;
277
278    fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
279    where
280        T: ?Sized + serde_core::Serialize,
281    {
282        self.0.serialize_element(value)
283    }
284
285    fn end(self) -> Result<Self::Ok, Self::Error> {
286        Ok(())
287    }
288}
289
290/// Deserializer used to extract flattened sequences from the end of another
291/// sequence.
292///
293/// Wrap an in-progress [`SeqAccess`](serde_core::de::SeqAccess) and
294/// deserialize a sequence-shaped value from the wrapper: the value
295/// consumes the remaining elements of the enclosing sequence. Target
296/// types that do not expect a sequence are an error.
297///
298/// The target must deserialize as a serde *seq* (e.g. `Vec<T>`);
299/// fixed-size tuples and arrays deserialize via `deserialize_tuple` and
300/// are rejected.
301pub struct FlattenedSequenceDeserializer<'a, S>(&'a mut S);
302
303impl<'a, S> FlattenedSequenceDeserializer<'a, S> {
304    /// Wrap the in-progress sequence access `seq_access`.
305    pub fn new<'de>(seq_access: &'a mut S) -> Self
306    where
307        S: serde_core::de::SeqAccess<'de>,
308    {
309        Self(seq_access)
310    }
311}
312
313impl<S> std::fmt::Debug for FlattenedSequenceDeserializer<'_, S> {
314    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
315        f.debug_struct("FlattenedSequenceDeserializer")
316            .finish_non_exhaustive()
317    }
318}
319
320impl<'de, S> Deserializer<'de> for FlattenedSequenceDeserializer<'_, S>
321where
322    S: serde_core::de::SeqAccess<'de>,
323{
324    type Error = S::Error;
325
326    fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value, S::Error>
327    where
328        V: serde_core::de::Visitor<'de>,
329    {
330        Err(S::Error::custom(
331            "FlattenedSequenceDeserializer only supports sequence-shaped target types",
332        ))
333    }
334
335    serde_core::forward_to_deserialize_any! {
336        bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string
337        bytes byte_buf option unit unit_struct newtype_struct tuple
338        tuple_struct map struct enum identifier ignored_any
339    }
340
341    fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
342    where
343        V: serde_core::de::Visitor<'de>,
344    {
345        visitor.visit_seq(self.0)
346    }
347}
348
349/// Always returns `true`; a predicate for `#[serde(skip_serializing_if)]`.
350///
351/// Use `#[serde(skip_serializing_if = "::json_serde::always")]` in place of
352/// `#[serde(skip_serializing)]` on fields with the [`Absent`] type when
353/// the containing type also derives `JsonSchema` (either schemars version).
354/// The two attribute forms serialize identically, but the schemas differ:
355/// schemars 0.8 (through 0.8.22) incorrectly marks `default` +
356/// `skip_serializing` fields as required, and schemars 1.0 (as of 1.2.2)
357/// spuriously annotates the field `writeOnly` (when, in fact, no value can be
358/// written!).
359///
360/// See [`Absent`].
361#[must_use]
362#[inline]
363pub fn always<T>(_: &T) -> bool {
364    true
365}
366
367/// Type for a value that *must* be absent.
368///
369/// This should be accompanied by serde attributes to indicate that:
370/// - the default value should be taken `#[serde(default)]`
371/// - it should never be serialized `#[serde(skip_serializing)]` (or
372///   `#[serde(skip_serializing_if = "::json_serde::always")]`; see
373///   [`always`])
374///
375/// Deserialization always fails--the field must not be present--and
376/// serialization fails if it is ever invoked, hence the attributes above.
377/// With the `schemars08` and `schemars1` features, `Absent`'s `JsonSchema`
378/// implementation is the `false` schema, which no value satisfies.
379#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
380pub struct Absent;
381
382impl serde_core::Serialize for Absent {
383    fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
384    where
385        S: Serializer,
386    {
387        use serde_core::ser::Error;
388        Err(S::Error::custom(
389            "field must be annotated with `skip_serializing` (or \
390             `skip_serializing_if = \"json_serde::always\"`)",
391        ))
392    }
393}
394
395impl<'de> Deserialize<'de> for Absent {
396    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
397    where
398        D: Deserializer<'de>,
399    {
400        use serde_core::de::Error;
401        // Chew up any inputs.
402        let _ = serde_core::de::IgnoredAny::deserialize(deserializer)?;
403        Err(D::Error::custom("field must be absent"))
404    }
405}
406
407#[cfg(feature = "schemars08")]
408impl schemars08::JsonSchema for Absent {
409    fn schema_name() -> String {
410        "Absent".to_string()
411    }
412
413    fn json_schema(_: &mut schemars08::r#gen::SchemaGenerator) -> schemars08::schema::Schema {
414        schemars08::schema::Schema::Bool(false)
415    }
416
417    fn is_referenceable() -> bool {
418        false
419    }
420}
421
422#[cfg(feature = "schemars1")]
423impl schemars1::JsonSchema for Absent {
424    fn schema_name() -> std::borrow::Cow<'static, str> {
425        std::borrow::Cow::Borrowed("Absent")
426    }
427
428    fn json_schema(_: &mut schemars1::SchemaGenerator) -> schemars1::Schema {
429        schemars1::Schema::from(false)
430    }
431
432    fn inline_schema() -> bool {
433        true
434    }
435}
436
437/// Models a fields that may be absent, null, or a value.
438///
439/// `Default` is required; it constructs the absent state.
440pub trait OptionalNullable: Default {
441    /// The type for the value when present and non-null.
442    type Target;
443
444    /// Returns true if the instance represents an absent value.
445    fn is_absent(&self) -> bool;
446
447    /// Construct a null.
448    fn null() -> Self;
449
450    /// Construct a value.
451    fn value(value: Self::Target) -> Self;
452}
453
454impl<T> OptionalNullable for Option<Option<T>> {
455    type Target = T;
456
457    fn is_absent(&self) -> bool {
458        self.is_none()
459    }
460
461    fn null() -> Self {
462        Some(None)
463    }
464
465    fn value(value: Self::Target) -> Self {
466        Some(Some(value))
467    }
468}
469
470#[cfg(test)]
471mod tests {
472    use serde::{Deserialize, Serialize, ser::SerializeSeq};
473
474    use crate::{Absent, FlattenedSequenceDeserializer, FlattenedSequenceSerializer};
475
476    #[test]
477    fn test_deserialize_some() {
478        #[derive(Debug, PartialEq, Serialize, Deserialize)]
479        struct Test {
480            #[serde(
481                default,
482                deserialize_with = "::json_serde::deserialize_some",
483                skip_serializing_if = "Option::is_none"
484            )]
485            field: Option<String>,
486        }
487
488        // An absent field yields None.
489        let de = serde_json::from_str::<Test>("{}").unwrap();
490        assert_eq!(de.field, None);
491
492        // A null value is an error: a String cannot be deserialized from
493        // null.
494        assert!(serde_json::from_str::<Test>(r#"{ "field": null }"#).is_err());
495
496        // A present value yields Some.
497        let de = serde_json::from_str::<Test>(r#"{ "field": "value" }"#).unwrap();
498        assert_eq!(de.field, Some("value".to_string()));
499    }
500
501    #[test]
502    fn test_deserialize_some_double_option() {
503        #[derive(Debug, PartialEq, Serialize, Deserialize)]
504        struct Test {
505            #[serde(
506                default,
507                deserialize_with = "::json_serde::deserialize_some",
508                skip_serializing_if = "Option::is_none"
509            )]
510            field: Option<Option<String>>,
511        }
512
513        // An absent field yields None.
514        let de = serde_json::from_str::<Test>("{}").unwrap();
515        assert_eq!(de.field, None);
516
517        // A null value yields Some(None).
518        let de = serde_json::from_str::<Test>(r#"{ "field": null }"#).unwrap();
519        assert_eq!(de.field, Some(None));
520
521        // A present value yields Some(Some(..)).
522        let de = serde_json::from_str::<Test>(r#"{ "field": "value" }"#).unwrap();
523        assert_eq!(de.field, Some(Some("value".to_string())));
524    }
525
526    #[test]
527    fn test_flatten_tuple_vec() {
528        #[derive(Debug, Eq, PartialEq)]
529        struct TestType(u32, String, Vec<u32>);
530
531        impl Serialize for TestType {
532            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
533            where
534                S: serde::Serializer,
535            {
536                let mut seq = serializer.serialize_seq(None)?;
537
538                seq.serialize_element(&self.0)?;
539                seq.serialize_element(&self.1)?;
540
541                self.2
542                    .serialize(FlattenedSequenceSerializer::new(&mut seq))?;
543
544                seq.end()
545            }
546        }
547
548        impl<'de> Deserialize<'de> for TestType {
549            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
550            where
551                D: serde::Deserializer<'de>,
552            {
553                struct Visitor;
554                impl<'de> serde::de::Visitor<'de> for Visitor {
555                    type Value = TestType;
556
557                    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
558                        formatter.write_str("a flattened tuple vec")
559                    }
560
561                    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
562                    where
563                        A: serde::de::SeqAccess<'de>,
564                    {
565                        let v_0 = seq.next_element()?.ok_or_else(|| {
566                            serde::de::Error::invalid_length(0, &"a tuple of size 2")
567                        })?;
568                        let v_1 = seq.next_element()?.ok_or_else(|| {
569                            serde::de::Error::invalid_length(1, &"a tuple of size 2")
570                        })?;
571
572                        let rest =
573                            Deserialize::deserialize(FlattenedSequenceDeserializer::new(&mut seq))?;
574
575                        Ok(TestType(v_0, v_1, rest))
576                    }
577                }
578                deserializer.deserialize_seq(Visitor)
579            }
580        }
581
582        let value = TestType(42, "Hello".to_string(), vec![1, 2, 3]);
583        let serialized = serde_json::to_string(&value).unwrap();
584
585        assert_eq!(serialized, "[42,\"Hello\",1,2,3]");
586
587        let de_value = serde_json::from_str::<TestType>(&serialized).unwrap();
588
589        assert_eq!(value, de_value);
590
591        let value = TestType(7, "World".to_string(), vec![]);
592        let serialized = serde_json::to_string(&value).unwrap();
593
594        assert_eq!(serialized, "[7,\"World\"]");
595
596        let de_value = serde_json::from_str::<TestType>(&serialized).unwrap();
597
598        assert_eq!(value, de_value);
599
600        let input = "[1, \"Two\", \"Three\", 4, 5, 6]";
601        let de_result = serde_json::from_str::<TestType>(input);
602        assert!(de_result.is_err());
603
604        let input = "[100]";
605        let de_result = serde_json::from_str::<TestType>(input);
606        let e = de_result.unwrap_err().to_string();
607        assert!(
608            e.starts_with("invalid length 1, expected a tuple of size 2"),
609            "{e}",
610        );
611
612        let input = "[1, \"Two\", \"Three\"]";
613        let de_result = serde_json::from_str::<TestType>(input);
614        let e = de_result.unwrap_err().to_string();
615        assert!(e.starts_with("invalid type"), "{e}");
616    }
617
618    /// Serialize `value` into a flattening serializer wrapped around a
619    /// JSON array and return the resulting error message.
620    fn flatten_ser_err(value: impl Serialize) -> String {
621        struct Wrapper<T>(T);
622
623        impl<T: Serialize> Serialize for Wrapper<T> {
624            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
625            where
626                S: serde::Serializer,
627            {
628                let mut seq = serializer.serialize_seq(None)?;
629                self.0
630                    .serialize(FlattenedSequenceSerializer::new(&mut seq))?;
631                seq.end()
632            }
633        }
634
635        serde_json::to_string(&Wrapper(value))
636            .unwrap_err()
637            .to_string()
638    }
639
640    #[test]
641    fn test_flatten_serializer_rejects_scalar() {
642        assert_eq!(
643            flatten_ser_err(42u32),
644            "FlattenedSequenceSerializer only supports sequence values, \
645             not u32",
646        );
647    }
648
649    #[test]
650    fn test_flatten_serializer_rejects_map() {
651        let map = std::collections::BTreeMap::from([("key", "value")]);
652        assert_eq!(
653            flatten_ser_err(map),
654            "FlattenedSequenceSerializer only supports sequence values, \
655             not map",
656        );
657    }
658
659    #[test]
660    fn test_flatten_deserializer_rejects_non_seq() {
661        #[derive(Debug)]
662        struct TestType;
663
664        impl<'de> Deserialize<'de> for TestType {
665            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
666            where
667                D: serde::Deserializer<'de>,
668            {
669                struct Visitor;
670                impl<'de> serde::de::Visitor<'de> for Visitor {
671                    type Value = TestType;
672
673                    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
674                        formatter.write_str("a sequence")
675                    }
676
677                    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
678                    where
679                        A: serde::de::SeqAccess<'de>,
680                    {
681                        // A non-seq target: u32 forwards to deserialize_any.
682                        let _ = u32::deserialize(FlattenedSequenceDeserializer::new(&mut seq))?;
683                        Ok(TestType)
684                    }
685                }
686                deserializer.deserialize_seq(Visitor)
687            }
688        }
689
690        let e = serde_json::from_str::<TestType>("[1, 2, 3]")
691            .unwrap_err()
692            .to_string();
693        assert!(
694            e.starts_with(
695                "FlattenedSequenceDeserializer only supports sequence-shaped target types"
696            ),
697            "{e}",
698        );
699    }
700
701    #[test]
702    fn test_absent_serialize_requires_skip() {
703        // Without skip_serializing (or the always predicate), serializing
704        // a struct containing Absent is an error.
705        #[derive(Serialize)]
706        struct Test {
707            absent: Absent,
708        }
709
710        let e = serde_json::to_string(&Test { absent: Absent })
711            .unwrap_err()
712            .to_string();
713        assert_eq!(
714            e,
715            "field must be annotated with `skip_serializing` (or \
716             `skip_serializing_if = \"json_serde::always\"`)",
717        );
718    }
719
720    #[test]
721    fn test_absent() {
722        #[derive(Serialize, Deserialize)]
723        struct Test {
724            #[serde(default, skip_serializing)]
725            absent: Absent,
726        }
727
728        let test = Test { absent: Absent };
729
730        assert_eq!(serde_json::to_string(&test).unwrap(), "{}");
731
732        let de = serde_json::from_str::<Test>("{}").unwrap();
733        let Absent = de.absent;
734        assert!(serde_json::from_str::<Test>(r#"{ "absent": null }"#).is_err());
735    }
736
737    #[cfg(feature = "schemars08")]
738    #[test]
739    fn test_absent_schema() {
740        // The `always` helper is necessary due to a bug present in schemars
741        // 0.8.22 where default + skip_serializing yields a required
742        // property. It is fixed in schemars 1.x.
743        #[derive(Serialize, Deserialize, schemars08::JsonSchema)]
744        #[schemars(crate = "schemars08")]
745        struct Test {
746            #[serde(skip_serializing_if = "crate::always")]
747            #[serde(default)]
748            absent: Absent,
749        }
750
751        let test = Test { absent: Absent };
752
753        assert_eq!(serde_json::to_string(&test).unwrap(), "{}");
754
755        let de = serde_json::from_str::<Test>("{}").unwrap();
756        let Absent = de.absent;
757        assert!(serde_json::from_str::<Test>(r#"{ "absent": null }"#).is_err());
758
759        let schema = schemars08::schema_for!(Test);
760        let expected = serde_json::json!({
761            "$schema": "http://json-schema.org/draft-07/schema#",
762            "title": "Test",
763            "type": "object",
764            "properties": {
765                "absent": false
766            }
767        });
768
769        assert_eq!(serde_json::to_value(&schema).unwrap(), expected);
770    }
771
772    #[cfg(feature = "schemars1")]
773    #[test]
774    fn test_absent_schema_v1() {
775        // The `always` form is the recommended annotation: a conditionally
776        // skipped field gets no `writeOnly` decoration, so the `false`
777        // schema survives intact.
778        #[derive(Serialize, Deserialize, schemars1::JsonSchema)]
779        #[schemars(crate = "schemars1")]
780        struct Test {
781            #[serde(default, skip_serializing_if = "crate::always")]
782            absent: Absent,
783        }
784
785        let test = Test { absent: Absent };
786
787        assert_eq!(serde_json::to_string(&test).unwrap(), "{}");
788
789        let de = serde_json::from_str::<Test>("{}").unwrap();
790        let Absent = de.absent;
791        assert!(serde_json::from_str::<Test>(r#"{ "absent": null }"#).is_err());
792
793        let schema = schemars1::schema_for!(Test);
794        let expected = serde_json::json!({
795            "$schema": "https://json-schema.org/draft/2020-12/schema",
796            "title": "Test",
797            "type": "object",
798            "properties": {
799                "absent": false
800            }
801        });
802
803        assert_eq!(serde_json::to_value(&schema).unwrap(), expected);
804    }
805}