#![cfg_attr(not(feature = "std"), no_std)]
extern crate self as defaulted;
pub use internal::Defaulted;
#[cfg(feature = "derive")]
pub use defaulted_derive::Defaulted;
#[cfg(all(feature = "derive", feature = "serde"))]
pub use defaulted_derive::skip_serializing_defaults;
mod impls;
mod internal;
#[cfg(test)]
#[allow(dead_code)]
mod tests
{
#[cfg(feature = "derive")]
mod derive_generic
{
use crate::Defaulted;
pub(super) struct NoDefault;
#[derive(Defaulted)]
pub(super) struct FooStruct<'a, T>
{
pub foo: u32,
pub bar: &'static str,
pub baz: Option<NoDefault>,
#[defaulted(ignore)]
pub _ignored: NoDefault,
#[defaulted(default = 17)]
pub fixed: i32,
#[defaulted(with = |s: &str| s.len() == 5)]
pub closure: &'a str,
#[defaulted(with = Option::is_some)]
pub func: Option<T>,
}
impl<T: Default> FooStruct<'_, T>
{
pub fn new() -> Self
{
Self {
foo: 0,
bar: "",
baz: None,
_ignored: NoDefault,
fixed: 17,
closure: "hello",
func: Some(T::default()),
}
}
}
#[derive(Defaulted)]
struct DelegateGeneric<T>
{
value: T,
}
#[test]
fn test_delegate_auto_bound()
{
let default_val = DelegateGeneric { value: 0u32 };
assert!(default_val.is_defaulted());
let non_default = DelegateGeneric { value: 42u32 };
assert!(!non_default.is_defaulted());
let empty_vec = DelegateGeneric::<Vec<NoDefault>> { value: Vec::new() };
assert!(empty_vec.is_defaulted());
}
#[test]
fn test_derive()
{
let default_value: FooStruct<String> = FooStruct::new();
let not_default_0: FooStruct<&'static str> = FooStruct {
foo: 1,
..FooStruct::new()
};
let not_default_1: FooStruct<&str> = FooStruct {
bar: "hello",
..FooStruct::new()
};
let not_default_2: FooStruct<&[u8]> = FooStruct {
baz: Some(NoDefault),
..FooStruct::new()
};
let fixed_mismatch: FooStruct<f32> = FooStruct {
fixed: 23,
..FooStruct::new()
};
let closure_match: FooStruct<i32> = FooStruct {
closure: "world",
..FooStruct::new()
};
let closure_mismatch: FooStruct<i32> = FooStruct {
closure: "worldly",
..FooStruct::new()
};
let func_mismatch: FooStruct<Vec<()>> = FooStruct {
func: None,
..FooStruct::new()
};
assert!(default_value.is_defaulted());
assert!(!not_default_0.is_defaulted());
assert!(!not_default_1.is_defaulted());
assert!(!not_default_2.is_defaulted());
assert!(!fixed_mismatch.is_defaulted());
assert!(closure_match.is_defaulted());
assert!(!closure_mismatch.is_defaulted());
assert!(!func_mismatch.is_defaulted());
}
}
#[cfg(feature = "derive")]
#[test]
fn test_derive_enum_unit()
{
use super::Defaulted;
#[derive(Defaulted)]
enum Status
{
#[defaulted(default)]
Idle,
Running,
Failed,
}
assert!(Status::Idle.is_defaulted());
assert!(!Status::Running.is_defaulted());
assert!(!Status::Failed.is_defaulted());
}
#[cfg(feature = "derive")]
#[test]
fn test_derive_enum_named()
{
use super::Defaulted;
#[derive(Defaulted)]
enum Value
{
#[defaulted(default)]
Default
{
label: String,
count: u32,
},
Custom(String),
}
let default_val = Value::Default {
label: String::new(),
count: 0,
};
let non_default_val = Value::Default {
label: "hello".into(),
count: 0,
};
let wrong_variant = Value::Custom("x".into());
assert!(default_val.is_defaulted());
assert!(!non_default_val.is_defaulted());
assert!(!wrong_variant.is_defaulted());
}
#[cfg(feature = "derive")]
#[test]
fn test_derive_enum_unnamed()
{
use super::Defaulted;
#[derive(Defaulted)]
enum Wrapper
{
#[defaulted(default)]
Pair(u32, String),
Single(u32),
}
let default_val = Wrapper::Pair(0, String::new());
let non_default_val = Wrapper::Pair(5, String::new());
let wrong_variant = Wrapper::Single(0);
assert!(default_val.is_defaulted());
assert!(!non_default_val.is_defaulted());
assert!(!wrong_variant.is_defaulted());
}
#[cfg(feature = "derive")]
#[test]
fn test_derive_enum_with_field_attrs()
{
use super::Defaulted;
#[derive(Defaulted)]
enum Config
{
#[defaulted(default)]
Standard
{
#[defaulted(default = 42)]
magic: i32,
#[defaulted(ignore)]
_opaque: u64,
#[defaulted(with = |s: &str| s == "on")]
mode: String,
},
Custom(String),
}
let default_val = Config::Standard {
magic: 42,
_opaque: 999,
mode: "on".into(),
};
let wrong_magic = Config::Standard {
magic: 0,
_opaque: 0,
mode: "on".into(),
};
let wrong_mode = Config::Standard {
magic: 42,
_opaque: 0,
mode: "off".into(),
};
let wrong_variant = Config::Custom("x".into());
assert!(default_val.is_defaulted());
assert!(!wrong_magic.is_defaulted());
assert!(!wrong_mode.is_defaulted());
assert!(!wrong_variant.is_defaulted());
}
#[cfg(feature = "derive")]
#[test]
fn test_impl_default()
{
use super::Defaulted;
use std::path::{PathBuf, Path};
#[derive(Debug, PartialEq, Defaulted)]
#[defaulted(Default)]
struct Settings
{
#[defaulted(default_ref = "codemon")]
theme: String,
#[defaulted(default = 4096)]
port: u16,
#[defaulted(default = 1.0)]
speed: f64,
#[defaulted(default = true)]
enabled: bool,
#[defaulted(default_ref = Path::new("/tmp/foo.txt"))]
path: PathBuf,
name: String,
}
let d = Settings::default();
assert_eq!(d.theme, "codemon");
assert_eq!(d.port, 4096);
assert!((d.speed - 1.0).abs() < f64::EPSILON);
assert!(d.enabled);
assert!(d.name.is_empty()); assert!(d.is_defaulted());
let modified = Settings {
port: 8080,
..Settings::default()
};
assert!(!modified.is_defaulted());
}
#[cfg(feature = "derive")]
mod nested_default
{
use crate::Defaulted;
#[derive(Debug, Default, PartialEq, Defaulted)]
struct Inner
{
count: u32,
}
#[derive(Debug, PartialEq, Defaulted)]
#[defaulted(Default)]
struct Outer
{
inner: Inner,
tags: Vec<String>,
}
#[test]
fn test_impl_default_with_nested()
{
let d = Outer::default();
assert_eq!(d.inner.count, 0);
assert!(d.tags.is_empty());
assert!(d.is_defaulted());
}
}
#[cfg(all(feature = "derive", feature = "serde"))]
mod skip_serializing_basic
{
use std::collections::HashSet;
use std::fmt;
use serde::Serialize;
use serde::ser::{self, SerializeStruct};
use crate::Defaulted;
fn serialized_fields<T: Serialize>(val: &T) -> HashSet<String>
{
struct FieldCollector;
struct FieldCollectorStruct(HashSet<String>);
#[derive(Debug)]
struct CollectorErr;
impl fmt::Display for CollectorErr
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "FieldCollector error")
}
}
impl std::error::Error for CollectorErr {}
impl ser::Error for CollectorErr
{
fn custom<T: fmt::Display>(_msg: T) -> Self
{
Self
}
}
impl ser::Serializer for FieldCollector
{
type Ok = HashSet<String>;
type Error = CollectorErr;
type SerializeSeq = ser::Impossible<Self::Ok, CollectorErr>;
type SerializeTuple = ser::Impossible<Self::Ok, CollectorErr>;
type SerializeTupleStruct = ser::Impossible<Self::Ok, CollectorErr>;
type SerializeTupleVariant = ser::Impossible<Self::Ok, CollectorErr>;
type SerializeMap = ser::Impossible<Self::Ok, CollectorErr>;
type SerializeStruct = FieldCollectorStruct;
type SerializeStructVariant = ser::Impossible<Self::Ok, CollectorErr>;
fn serialize_struct(
self,
_name: &'static str,
_len: usize,
) -> Result<FieldCollectorStruct, CollectorErr>
{
Ok(FieldCollectorStruct(HashSet::new()))
}
fn serialize_bool(self, _: bool) -> Result<Self::Ok, CollectorErr> { Err(CollectorErr) }
fn serialize_i8(self, _: i8) -> Result<Self::Ok, CollectorErr> { Err(CollectorErr) }
fn serialize_i16(self, _: i16) -> Result<Self::Ok, CollectorErr> { Err(CollectorErr) }
fn serialize_i32(self, _: i32) -> Result<Self::Ok, CollectorErr> { Err(CollectorErr) }
fn serialize_i64(self, _: i64) -> Result<Self::Ok, CollectorErr> { Err(CollectorErr) }
fn serialize_u8(self, _: u8) -> Result<Self::Ok, CollectorErr> { Err(CollectorErr) }
fn serialize_u16(self, _: u16) -> Result<Self::Ok, CollectorErr> { Err(CollectorErr) }
fn serialize_u32(self, _: u32) -> Result<Self::Ok, CollectorErr> { Err(CollectorErr) }
fn serialize_u64(self, _: u64) -> Result<Self::Ok, CollectorErr> { Err(CollectorErr) }
fn serialize_f32(self, _: f32) -> Result<Self::Ok, CollectorErr> { Err(CollectorErr) }
fn serialize_f64(self, _: f64) -> Result<Self::Ok, CollectorErr> { Err(CollectorErr) }
fn serialize_char(self, _: char) -> Result<Self::Ok, CollectorErr> { Err(CollectorErr) }
fn serialize_str(self, _: &str) -> Result<Self::Ok, CollectorErr> { Err(CollectorErr) }
fn serialize_bytes(self, _: &[u8]) -> Result<Self::Ok, CollectorErr> { Err(CollectorErr) }
fn serialize_none(self) -> Result<Self::Ok, CollectorErr> { Err(CollectorErr) }
fn serialize_some<T: Serialize + ?Sized>(self, _: &T) -> Result<Self::Ok, CollectorErr> { Err(CollectorErr) }
fn serialize_unit(self) -> Result<Self::Ok, CollectorErr> { Err(CollectorErr) }
fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, CollectorErr> { Err(CollectorErr) }
fn serialize_unit_variant(self, _: &'static str, _: u32, _: &'static str) -> Result<Self::Ok, CollectorErr> { Err(CollectorErr) }
fn serialize_newtype_struct<T: Serialize + ?Sized>(self, _: &'static str, _: &T) -> Result<Self::Ok, CollectorErr> { Err(CollectorErr) }
fn serialize_newtype_variant<T: Serialize + ?Sized>(self, _: &'static str, _: u32, _: &'static str, _: &T) -> Result<Self::Ok, CollectorErr> { Err(CollectorErr) }
fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, CollectorErr> { Err(CollectorErr) }
fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple, CollectorErr> { Err(CollectorErr) }
fn serialize_tuple_struct(self, _: &'static str, _: usize) -> Result<Self::SerializeTupleStruct, CollectorErr> { Err(CollectorErr) }
fn serialize_tuple_variant(self, _: &'static str, _: u32, _: &'static str, _: usize) -> Result<Self::SerializeTupleVariant, CollectorErr> { Err(CollectorErr) }
fn serialize_map(self, _: Option<usize>) -> Result<Self::SerializeMap, CollectorErr> { Err(CollectorErr) }
fn serialize_struct_variant(self, _: &'static str, _: u32, _: &'static str, _: usize) -> Result<Self::SerializeStructVariant, CollectorErr> { Err(CollectorErr) }
}
impl SerializeStruct for FieldCollectorStruct
{
type Ok = HashSet<String>;
type Error = CollectorErr;
fn serialize_field<T: Serialize + ?Sized>(
&mut self,
key: &'static str,
_value: &T,
) -> Result<(), CollectorErr>
{
self.0.insert(key.to_owned());
Ok(())
}
fn end(self) -> Result<HashSet<String>, CollectorErr>
{
Ok(self.0)
}
}
val.serialize(FieldCollector).unwrap()
}
#[defaulted::skip_serializing_defaults]
#[derive(Debug, Serialize, Defaulted)]
#[defaulted(Default)]
struct Config
{
name: Option<String>,
#[defaulted(default = "codemon")]
theme: String,
#[defaulted(default = 7)]
days: u32,
tags: Vec<String>,
}
#[test]
fn default_fields_skipped()
{
let c = Config::default();
assert!(c.is_defaulted());
let fields = serialized_fields(&c);
assert!(fields.is_empty(), "expected no fields, got {fields:?}");
}
#[test]
fn non_default_fields_present()
{
let c = Config {
theme: "dark".into(),
..Config::default()
};
let fields = serialized_fields(&c);
assert!(fields.contains("theme"));
assert!(!fields.contains("name"));
assert!(!fields.contains("days"));
assert!(!fields.contains("tags"));
}
#[test]
fn custom_default_skipped()
{
let c = Config {
days: 7,
..Config::default()
};
let fields = serialized_fields(&c);
assert!(!fields.contains("days"));
}
#[test]
fn custom_default_serialized_when_different()
{
let c = Config {
days: 5,
..Config::default()
};
let fields = serialized_fields(&c);
assert!(fields.contains("days"));
}
#[defaulted::skip_serializing_defaults]
#[derive(Debug, Serialize, Defaulted)]
#[defaulted(Default)]
struct WithIgnored
{
#[defaulted(ignore)]
always: u32,
normal: u32,
}
#[test]
fn ignored_field_always_serialized()
{
let w = WithIgnored::default();
let fields = serialized_fields(&w);
assert!(fields.contains("always"), "ignored field should serialize");
assert!(!fields.contains("normal"), "default field should be skipped");
}
#[expect(clippy::trivially_copy_pass_by_ref)]
fn custom_check(v: &u32) -> bool
{
*v > 100
}
#[defaulted::skip_serializing_defaults]
#[derive(Debug, Serialize, Defaulted)]
#[defaulted(Default)]
struct WithExistingSkip
{
#[serde(skip_serializing_if = "custom_check")]
special: u32,
normal: u32,
}
#[test]
fn existing_skip_preserved()
{
let w = WithExistingSkip {
special: 200,
normal: 0,
};
let fields = serialized_fields(&w);
assert!(!fields.contains("special"));
assert!(!fields.contains("normal"));
}
#[expect(clippy::trivially_copy_pass_by_ref)]
fn is_positive(v: &i32) -> bool
{
*v > 0
}
#[defaulted::skip_serializing_defaults]
#[derive(Debug, Serialize, Defaulted)]
struct WithFunc
{
#[defaulted(with = is_positive)]
score: i32,
}
#[test]
fn with_func_skips_when_true()
{
let w = WithFunc { score: 5 };
let fields = serialized_fields(&w);
assert!(!fields.contains("score"));
}
#[test]
fn with_func_serializes_when_false()
{
let w = WithFunc { score: -1 };
let fields = serialized_fields(&w);
assert!(fields.contains("score"));
}
#[defaulted::skip_serializing_defaults]
#[derive(Debug, Serialize, Defaulted)]
#[defaulted(Default)]
struct StringDefault
{
#[defaulted(default = "hello")]
greeting: String,
}
#[test]
fn string_default_skipped()
{
let s = StringDefault::default();
let fields = serialized_fields(&s);
assert!(fields.is_empty());
}
#[test]
fn string_non_default_serialized()
{
let s = StringDefault {
greeting: "world".into(),
};
let fields = serialized_fields(&s);
assert!(fields.contains("greeting"));
}
#[defaulted::skip_serializing_defaults]
#[derive(Debug, Serialize, Defaulted)]
#[defaulted(Default)]
struct GenericConfig<T>
{
label: String,
value: T,
#[defaulted(default = 10)]
limit: u32,
}
#[test]
fn generic_default_all_skipped()
{
let c: GenericConfig<u32> = GenericConfig::default();
assert!(c.is_defaulted());
let fields = serialized_fields(&c);
assert!(fields.is_empty(), "expected no fields, got {fields:?}");
}
#[test]
fn generic_non_default_fields_present()
{
let c = GenericConfig {
label: "test".into(),
value: 42u32,
limit: 10,
};
let fields = serialized_fields(&c);
assert!(fields.contains("label"));
assert!(fields.contains("value"));
assert!(!fields.contains("limit"), "default limit should be skipped");
}
}
#[cfg(all(feature = "derive", feature = "serde", feature = "serde-json"))]
mod skip_serializing
{
use serde::{Deserialize, Serialize};
use crate::Defaulted;
#[defaulted::skip_serializing_defaults]
#[derive(Debug, Serialize, Defaulted)]
#[defaulted(Default)]
struct Config
{
name: Option<String>,
#[defaulted(default = "codemon")]
theme: String,
#[defaulted(default = 7)]
days: u32,
tags: Vec<String>,
}
#[test]
fn default_serializes_empty()
{
let c = Config::default();
assert!(c.is_defaulted());
let json = serde_json::to_value(&c).unwrap();
let obj = json.as_object().unwrap();
assert!(obj.is_empty(), "expected empty object, got {obj:?}");
}
#[test]
fn non_default_fields_serialize()
{
let c = Config {
theme: "dark".into(),
..Config::default()
};
let json = serde_json::to_value(&c).unwrap();
let obj = json.as_object().unwrap();
assert_eq!(obj.get("theme").unwrap(), "dark");
assert!(!obj.contains_key("name"));
assert!(!obj.contains_key("days"));
assert!(!obj.contains_key("tags"));
}
#[test]
fn custom_default_skipped_when_matching()
{
let c = Config {
days: 7,
..Config::default()
};
let json = serde_json::to_value(&c).unwrap();
assert!(!json.as_object().unwrap().contains_key("days"));
}
#[test]
fn custom_default_serialized_when_different()
{
let c = Config {
days: 5,
..Config::default()
};
let json = serde_json::to_value(&c).unwrap();
assert_eq!(json.as_object().unwrap().get("days").unwrap(), 5);
}
#[defaulted::skip_serializing_defaults]
#[derive(Debug, Serialize, Defaulted)]
#[defaulted(Default)]
struct WithIgnored
{
#[defaulted(ignore)]
always: u32,
normal: u32,
}
#[test]
fn ignored_field_always_serializes()
{
let w = WithIgnored::default();
let json = serde_json::to_value(&w).unwrap();
let obj = json.as_object().unwrap();
assert!(obj.contains_key("always"), "ignored field should serialize");
assert!(
!obj.contains_key("normal"),
"default field should be skipped"
);
}
#[expect(clippy::trivially_copy_pass_by_ref)]
fn custom_check(v: &u32) -> bool
{
*v > 100
}
#[defaulted::skip_serializing_defaults]
#[derive(Debug, Serialize, Defaulted)]
#[defaulted(Default)]
struct WithExistingSkip
{
#[serde(skip_serializing_if = "custom_check")]
special: u32,
normal: u32,
}
#[test]
fn existing_skip_preserved()
{
let w = WithExistingSkip {
special: 200,
normal: 0,
};
let json = serde_json::to_value(&w).unwrap();
let obj = json.as_object().unwrap();
assert!(!obj.contains_key("special"));
assert!(!obj.contains_key("normal"));
}
#[expect(clippy::trivially_copy_pass_by_ref)]
fn is_positive(v: &i32) -> bool
{
*v > 0
}
#[defaulted::skip_serializing_defaults]
#[derive(Debug, Serialize, Defaulted)]
struct WithFunc
{
#[defaulted(with = is_positive)]
score: i32,
}
#[test]
fn with_func_skips_when_true()
{
let w = WithFunc { score: 5 };
let json = serde_json::to_value(&w).unwrap();
assert!(
!json.as_object().unwrap().contains_key("score"),
"should skip when func returns true"
);
}
#[test]
fn with_func_serializes_when_false()
{
let w = WithFunc { score: -1 };
let json = serde_json::to_value(&w).unwrap();
assert_eq!(json.as_object().unwrap().get("score").unwrap(), -1);
}
#[defaulted::skip_serializing_defaults]
#[derive(Debug, PartialEq, Serialize, serde::Deserialize)]
#[serde(default)]
struct Standalone
{
#[defaulted(default = 42)]
magic: u32,
#[defaulted(ignore)]
opaque: u32,
normal: String,
}
impl Default for Standalone
{
fn default() -> Self
{
Self {
magic: 42,
opaque: 0,
normal: String::new(),
}
}
}
#[test]
fn standalone_skips_matching_default()
{
let s = Standalone::default();
let json = serde_json::to_value(&s).unwrap();
let obj = json.as_object().unwrap();
assert!(!obj.contains_key("magic"), "should skip default magic");
assert!(obj.contains_key("opaque"), "ignored always serializes");
assert!(
!obj.contains_key("normal"),
"empty string is default via Defaulted"
);
}
#[test]
fn standalone_serializes_non_default()
{
let s = Standalone {
magic: 99,
opaque: 0,
normal: "hello".into(),
};
let json = serde_json::to_value(&s).unwrap();
let obj = json.as_object().unwrap();
assert_eq!(obj.get("magic").unwrap(), 99);
assert_eq!(obj.get("normal").unwrap(), "hello");
}
#[test]
fn standalone_roundtrip_defaults()
{
let original = Standalone::default();
let json = serde_json::to_value(&original).unwrap();
assert_eq!(json, serde_json::json!({"opaque": 0}));
let restored: Standalone = serde_json::from_value(json).unwrap();
assert_eq!(restored, original);
}
#[test]
fn standalone_roundtrip_non_defaults()
{
let original = Standalone {
magic: 99,
opaque: 7,
normal: "hello".into(),
};
let json = serde_json::to_value(&original).unwrap();
let restored: Standalone = serde_json::from_value(json).unwrap();
assert_eq!(restored, original);
}
#[test]
fn standalone_deserialize_missing_fields()
{
let json = serde_json::json!({"opaque": 5});
let s: Standalone = serde_json::from_value(json).unwrap();
assert_eq!(s.magic, 42, "missing magic should default to 42");
assert_eq!(s.opaque, 5);
assert_eq!(s.normal, "", "missing normal should default to empty");
}
#[defaulted::skip_serializing_defaults]
#[derive(Debug, Serialize, Defaulted)]
#[defaulted(Default)]
struct StringDefault
{
#[defaulted(default = "hello")]
greeting: String,
}
#[test]
fn string_default_skipped()
{
let s = StringDefault::default();
let json = serde_json::to_value(&s).unwrap();
assert!(json.as_object().unwrap().is_empty());
}
#[test]
fn string_non_default_serialized()
{
let s = StringDefault {
greeting: "world".into(),
};
let json = serde_json::to_value(&s).unwrap();
assert_eq!(json.as_object().unwrap().get("greeting").unwrap(), "world");
}
#[derive(Serialize, Deserialize)] #[serde(transparent)]
struct NoDefault(i32);
#[defaulted::skip_serializing_defaults]
#[derive(Serialize, Deserialize)] struct NonDefaultableConfig
{
#[defaulted(ignore)]
foo: NoDefault,
#[defaulted(default = 7)]
days_per_week: u32,
}
#[test]
fn test_non_default()
{
let config: NonDefaultableConfig =
serde_json::from_value(serde_json::json!({"foo": -17})).unwrap();
assert_eq!(config.days_per_week, 7);
let config_json = serde_json::to_value(&config).unwrap();
assert!(
!config_json
.as_object()
.unwrap()
.contains_key("days_per_week")
);
}
#[defaulted::skip_serializing_defaults]
#[derive(Debug, Serialize, Defaulted)]
#[defaulted(Default)]
struct GenericConfig<T>
{
label: String,
value: T,
#[defaulted(default = 10)]
limit: u32,
}
#[test]
fn generic_default_serializes_empty()
{
let c: GenericConfig<u32> = GenericConfig::default();
assert!(c.is_defaulted());
let json = serde_json::to_value(&c).unwrap();
let obj = json.as_object().unwrap();
assert!(obj.is_empty(), "expected empty object, got {obj:?}");
}
#[test]
fn generic_non_default_serializes()
{
let c = GenericConfig {
label: "test".into(),
value: 42u32,
limit: 10,
};
let json = serde_json::to_value(&c).unwrap();
let obj = json.as_object().unwrap();
assert_eq!(obj.get("label").unwrap(), "test");
assert_eq!(obj.get("value").unwrap(), 42);
assert!(
!obj.contains_key("limit"),
"default limit should be skipped"
);
}
#[test]
fn generic_custom_default_round_trips()
{
let c = GenericConfig::<String> {
limit: 5,
..GenericConfig::default()
};
let json = serde_json::to_value(&c).unwrap();
let obj = json.as_object().unwrap();
assert_eq!(obj.get("limit").unwrap(), 5);
assert!(!obj.contains_key("label"));
assert!(!obj.contains_key("value"));
}
#[test]
fn test_deref()
{
use std::borrow::Cow;
let empty_owned: Cow<'static, str> = Cow::Owned(String::new());
let empty_borrowed = Cow::Borrowed("");
let nonempty_owned: Cow<'static, str> = Cow::Owned("foo".to_owned());
let nonempty_borrowed = Cow::Borrowed("foo");
assert!(empty_owned.is_defaulted());
assert!(empty_borrowed.is_defaulted());
assert!(!nonempty_owned.is_defaulted());
assert!(!nonempty_borrowed.is_defaulted());
}
}
}