1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
//!
//! This crate defines "nothing" in terms of `serde` data model
//! and allows checking values and create such values using only `Serialize` and `Deserialize` traits.
//!
//! # Motivation
//!
//! This crate is designed to generalize serialization pattern
//! where struct fields with None/empty/default values are skipped on serialization
//! and constructed on deserialization when missing.
//!
//! Usually this pattern is coded using `#[serde(default, skip_serializing_if = "Option::is_none/Vec::is_empty/is_default")]`.
//! Where `is_default` is a function defined as
//! ```rust
//! fn is_default<T: Default + PartialEq>(value: &T) -> bool {
//!     *value == T::default()
//! }
//! ```
//!
//! The pattern works very well for field with concrete types and generic wrappers like `Option`, `Vec` and similar.
//!
//! But using `#[serde(default)]` on field with generic type `T` would require `Default` bound added to the `Deserialize` impl.
//! And `#[serde(skip_serializing_if = "is_default")]` would require `T: Default + PartialEq` bound added to the `Serialize` impl.
//!
//! This crate allows to implement this pattern without additional bounds.
//! Even more, it allows specialize for types that can be skipped.
//! That is, if field has type `T` that does not even have a value that would be appropriate to skip,
//! the code will continue work correctly and would simply always serialize the field and require the data for deserialization.
//!
//! # Magic? No, science!
//!
//! This crate provides stateless `Nothing` type which is a special kind of `serde::Serializer` or `serde::Deserializer`.
//! `Nothing` can be used to serialize and deserialize "nothing" values.
//! "Nothing" values are `None`, empty collections, units,
//! structs and tuples where all fields are "nothing"
//!
//! Serializing a "non-nothing" value with `Nothing` always fails.
//!
//! As deserializer `Nothing` would visit most appropriate `Visitor` method
//! with matching kind of nothingness, like `None`, empty slice/sequence/map,
//! single-variant enum with nothing in discriminant and nothing in payload,
//! `0` numeric value etc.
//!
//! User would most probably want to use a shortcut and utilize `is_nothing` function for serialization
//! and `from_nothing` function for deserialization.
//!

#![cfg_attr(not(feature = "std"), no_std)]

mod de;
mod ser;

pub use self::{de::NothingDeserializeError, ser::NothingSerializeError};

/// Serializer to serialize values into and from nothing.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Nothing;

/// Returns true if the value matches definition of "nothing".
/// Typically deserializing from `Nothing` would yield same value.
#[inline]
pub fn is_nothing<T: ?Sized>(value: &T) -> bool
where
    T: serde::ser::Serialize,
{
    value.serialize(Nothing).is_ok()
}

/// Returns some "nothing" value of the type.
/// Or none if failed to create one.
#[inline]
pub fn from_nothing<'de, T>() -> Option<T>
where
    T: serde::de::Deserialize<'de>,
{
    T::deserialize(Nothing).ok()
}

#[cfg(test)]
mod tests {
    use core::fmt::Debug;

    use serde::{Deserialize, Serialize};

    use crate::{is_nothing, Nothing};

    #[derive(Debug, PartialEq, Eq, serde_derive::Serialize, serde_derive::Deserialize)]
    struct Struct {
        number: u32,
        string: &'static str,
    }

    #[cfg(test)]
    fn check_roundtrip<'de, T: ?Sized + Serialize + Deserialize<'de> + PartialEq + Debug>(
        value: &T,
    ) {
        assert!(is_nothing(value));
        let () = value.serialize(Nothing).unwrap();
        assert_eq!(Ok(value), T::deserialize(Nothing).as_ref());
    }

    #[test]
    fn test_unit() {
        check_roundtrip(&());
    }

    #[test]
    fn test_numbers() {
        check_roundtrip(&0);
    }

    #[test]
    #[should_panic]
    fn test_numbers_fail() {
        check_roundtrip(&1);
    }

    #[test]
    fn test_string() {
        check_roundtrip(&"");
    }

    #[test]
    #[should_panic]
    fn test_string_fail() {
        check_roundtrip(&"a");
    }

    #[test]
    fn test_slice() {
        check_roundtrip(&&[0u8][..0]);
    }

    #[test]
    #[should_panic]
    fn test_slice_fail() {
        check_roundtrip(&&[0u8][..]);
    }

    #[test]
    fn test_array() {
        check_roundtrip(&[0, 0, 0]);
    }

    #[test]
    #[should_panic]
    fn test_array_fail() {
        check_roundtrip(&[0, 0, 1]);
    }

    #[test]
    fn test_tuple() {
        check_roundtrip(&(0, ""))
    }

    #[test]
    #[should_panic]
    fn test_tuple_fail() {
        check_roundtrip(&(0, "a"))
    }

    #[test]
    fn test_struct() {
        check_roundtrip(&Struct {
            number: 0,
            string: "",
        })
    }

    #[test]
    #[should_panic]
    fn test_struct_fail() {
        check_roundtrip(&Struct {
            number: 1,
            string: "",
        })
    }
}