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: "",
})
}
}