// These just test that serde_derive is able to produce code that compiles // successfully when there are a variety of generics and non-(de)serializable // types involved. #![deny(warnings)] #![allow( unknown_lints, mixed_script_confusables, clippy::derive_partial_eq_without_eq, clippy::extra_unused_type_parameters, clippy::items_after_statements, clippy::missing_errors_doc, clippy::missing_panics_doc, clippy::must_use_candidate, // Clippy bug: https://github.com/rust-lang/rust-clippy/issues/7422 clippy::nonstandard_macro_braces, clippy::ptr_arg, clippy::too_many_lines, clippy::trivially_copy_pass_by_ref, clippy::type_repetition_in_bounds )] use serde::de::DeserializeOwned; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::borrow::Cow; use std::marker::PhantomData; use std::option::Option as StdOption; use std::result::Result as StdResult; // Try to trip up the generated code if it fails to use fully qualified paths. #[allow(dead_code)] struct Result; #[allow(dead_code)] struct Ok; #[allow(dead_code)] struct Err; #[allow(dead_code)] struct Option; #[allow(dead_code)] struct Some; #[allow(dead_code)] struct None; ////////////////////////////////////////////////////////////////////////// #[test] fn test_gen() { #[derive(Serialize, Deserialize)] struct With { t: T, #[serde(serialize_with = "ser_x", deserialize_with = "de_x")] x: X, } assert::>(); #[derive(Serialize, Deserialize)] struct WithTogether { t: T, #[serde(with = "both_x")] x: X, } assert::>(); #[derive(Serialize, Deserialize)] struct WithRef<'a, T: 'a> { #[serde(skip_deserializing)] t: StdOption<&'a T>, #[serde(serialize_with = "ser_x", deserialize_with = "de_x")] x: X, } assert::>(); #[derive(Serialize, Deserialize)] struct PhantomX { x: PhantomData, } assert::(); #[derive(Serialize, Deserialize)] struct PhantomT { t: PhantomData, } assert::>(); #[derive(Serialize, Deserialize)] struct NoBounds { t: T, option: StdOption, boxed: Box, option_boxed: StdOption>, } assert::>(); #[derive(Serialize, Deserialize)] enum EnumWith { Unit, Newtype(#[serde(serialize_with = "ser_x", deserialize_with = "de_x")] X), Tuple( T, #[serde(serialize_with = "ser_x", deserialize_with = "de_x")] X, ), Struct { t: T, #[serde(serialize_with = "ser_x", deserialize_with = "de_x")] x: X, }, } assert::>(); #[derive(Serialize)] struct MultipleRef<'a, 'b, 'c, T> where T: 'c, 'c: 'b, 'b: 'a, { t: T, rrrt: &'a &'b &'c T, } assert_ser::>(); #[derive(Serialize, Deserialize)] struct Newtype(#[serde(serialize_with = "ser_x", deserialize_with = "de_x")] X); assert::(); #[derive(Serialize, Deserialize)] struct Tuple( T, #[serde(serialize_with = "ser_x", deserialize_with = "de_x")] X, ); assert::>(); #[derive(Serialize, Deserialize)] enum TreeNode { Split { left: Box>, right: Box>, }, Leaf { data: D, }, } assert::>(); #[derive(Serialize, Deserialize)] struct ListNode { data: D, next: Box>, } assert::>(); #[derive(Serialize, Deserialize)] struct RecursiveA { b: Box, } assert::(); #[derive(Serialize, Deserialize)] enum RecursiveB { A(RecursiveA), } assert::(); #[derive(Serialize, Deserialize)] struct RecursiveGenericA { t: T, b: Box>, } assert::>(); #[derive(Serialize, Deserialize)] enum RecursiveGenericB { T(T), A(RecursiveGenericA), } assert::>(); #[derive(Serialize)] struct OptionStatic<'a> { a: StdOption<&'a str>, b: StdOption<&'static str>, } assert_ser::(); #[derive(Serialize, Deserialize)] #[serde(bound = "D: SerializeWith + DeserializeWith")] struct WithTraits1 { #[serde( serialize_with = "SerializeWith::serialize_with", deserialize_with = "DeserializeWith::deserialize_with" )] d: D, #[serde( serialize_with = "SerializeWith::serialize_with", deserialize_with = "DeserializeWith::deserialize_with", bound = "E: SerializeWith + DeserializeWith" )] e: E, } assert::>(); #[derive(Serialize, Deserialize)] #[serde(bound(serialize = "D: SerializeWith", deserialize = "D: DeserializeWith"))] struct WithTraits2 { #[serde( serialize_with = "SerializeWith::serialize_with", deserialize_with = "DeserializeWith::deserialize_with" )] d: D, #[serde( serialize_with = "SerializeWith::serialize_with", bound(serialize = "E: SerializeWith") )] #[serde( deserialize_with = "DeserializeWith::deserialize_with", bound(deserialize = "E: DeserializeWith") )] e: E, } assert::>(); #[derive(Serialize, Deserialize)] #[serde(bound = "D: SerializeWith + DeserializeWith")] enum VariantWithTraits1 { #[serde( serialize_with = "SerializeWith::serialize_with", deserialize_with = "DeserializeWith::deserialize_with" )] D(D), #[serde( serialize_with = "SerializeWith::serialize_with", deserialize_with = "DeserializeWith::deserialize_with", bound = "E: SerializeWith + DeserializeWith" )] E(E), } assert::>(); #[derive(Serialize, Deserialize)] #[serde(bound(serialize = "D: SerializeWith", deserialize = "D: DeserializeWith"))] enum VariantWithTraits2 { #[serde( serialize_with = "SerializeWith::serialize_with", deserialize_with = "DeserializeWith::deserialize_with" )] D(D), #[serde( serialize_with = "SerializeWith::serialize_with", bound(serialize = "E: SerializeWith") )] #[serde( deserialize_with = "DeserializeWith::deserialize_with", bound(deserialize = "E: DeserializeWith") )] E(E), } assert::>(); #[derive(Serialize, Deserialize)] struct CowStr<'a>(Cow<'a, str>); assert::(); #[derive(Serialize, Deserialize)] #[serde(bound(deserialize = "T::Owned: DeserializeOwned"))] struct CowT<'a, T: ?Sized + 'a + ToOwned>(Cow<'a, T>); assert::>(); #[derive(Serialize, Deserialize)] struct EmptyStruct {} assert::(); #[derive(Serialize, Deserialize)] enum EmptyEnumVariant { EmptyStruct {}, } assert::(); #[derive(Serialize, Deserialize)] struct NonAsciiIdents { σ: f64, } #[derive(Serialize, Deserialize)] struct EmptyBraced {} #[derive(Serialize, Deserialize)] #[serde(deny_unknown_fields)] struct EmptyBracedDenyUnknown {} #[derive(Serialize, Deserialize)] struct BracedSkipAll { #[serde(skip_deserializing)] f: u8, } #[derive(Serialize, Deserialize)] #[serde(deny_unknown_fields)] struct BracedSkipAllDenyUnknown { #[serde(skip_deserializing)] f: u8, } #[derive(Serialize, Deserialize)] struct EmptyTuple(); #[derive(Serialize, Deserialize)] #[serde(deny_unknown_fields)] struct EmptyTupleDenyUnknown(); #[derive(Serialize, Deserialize)] struct TupleSkipAll(#[serde(skip_deserializing)] u8); #[derive(Serialize, Deserialize)] #[serde(deny_unknown_fields)] struct TupleSkipAllDenyUnknown(#[serde(skip_deserializing)] u8); #[derive(Serialize, Deserialize)] enum EmptyEnum {} #[derive(Serialize, Deserialize)] #[serde(deny_unknown_fields)] enum EmptyEnumDenyUnknown {} #[derive(Serialize, Deserialize)] enum EnumSkipAll { #[serde(skip_deserializing)] #[allow(dead_code)] Variant, } #[derive(Serialize, Deserialize)] enum EmptyVariants { Braced {}, Tuple(), BracedSkip { #[serde(skip_deserializing)] f: u8, }, TupleSkip(#[serde(skip_deserializing)] u8), } #[derive(Serialize, Deserialize)] #[serde(deny_unknown_fields)] enum EmptyVariantsDenyUnknown { Braced {}, Tuple(), BracedSkip { #[serde(skip_deserializing)] f: u8, }, TupleSkip(#[serde(skip_deserializing)] u8), } #[derive(Serialize, Deserialize)] #[serde(deny_unknown_fields)] struct UnitDenyUnknown; #[derive(Serialize, Deserialize)] struct EmptyArray { empty: [X; 0], } enum Or { A(A), B(B), } #[derive(Serialize, Deserialize)] #[serde(untagged, remote = "Or")] enum OrDef { A(A), B(B), } struct Str<'a>(&'a str); #[derive(Serialize, Deserialize)] #[serde(remote = "Str")] struct StrDef<'a>(&'a str); #[derive(Serialize, Deserialize)] struct Remote<'a> { #[serde(with = "OrDef")] or: Or, #[serde(borrow, with = "StrDef")] s: Str<'a>, } #[derive(Serialize, Deserialize)] enum BorrowVariant<'a> { #[serde(borrow, with = "StrDef")] S(Str<'a>), } mod vis { use serde::{Deserialize, Serialize}; pub struct S; #[derive(Serialize, Deserialize)] #[serde(remote = "S")] pub struct SDef; } // This would not work if SDef::serialize / deserialize are private. #[derive(Serialize, Deserialize)] struct RemoteVisibility { #[serde(with = "vis::SDef")] s: vis::S, } #[derive(Serialize, Deserialize)] #[serde(remote = "Self")] struct RemoteSelf; #[derive(Serialize, Deserialize)] enum ExternallyTaggedVariantWith { #[serde(serialize_with = "ser_x")] #[serde(deserialize_with = "de_x")] #[allow(dead_code)] Newtype(X), #[serde(serialize_with = "serialize_some_other_variant")] #[serde(deserialize_with = "deserialize_some_other_variant")] #[allow(dead_code)] Tuple(String, u8), #[serde(serialize_with = "ser_x")] #[serde(deserialize_with = "de_x")] #[allow(dead_code)] Struct1 { x: X }, #[serde(serialize_with = "serialize_some_other_variant")] #[serde(deserialize_with = "deserialize_some_other_variant")] #[allow(dead_code)] Struct { f1: String, f2: u8 }, #[serde(serialize_with = "serialize_some_unit_variant")] #[serde(deserialize_with = "deserialize_some_unit_variant")] #[allow(dead_code)] Unit, } assert_ser::(); #[derive(Serialize, Deserialize)] #[serde(tag = "t")] enum InternallyTaggedVariantWith { #[serde(serialize_with = "ser_x")] #[serde(deserialize_with = "de_x")] #[allow(dead_code)] Newtype(X), #[serde(serialize_with = "ser_x")] #[serde(deserialize_with = "de_x")] #[allow(dead_code)] Struct1 { x: X }, #[serde(serialize_with = "serialize_some_other_variant")] #[serde(deserialize_with = "deserialize_some_other_variant")] #[allow(dead_code)] Struct { f1: String, f2: u8 }, #[serde(serialize_with = "serialize_some_unit_variant")] #[serde(deserialize_with = "deserialize_some_unit_variant")] #[allow(dead_code)] Unit, } assert_ser::(); #[derive(Serialize, Deserialize)] #[serde(tag = "t", content = "c")] enum AdjacentlyTaggedVariantWith { #[serde(serialize_with = "ser_x")] #[serde(deserialize_with = "de_x")] #[allow(dead_code)] Newtype(X), #[serde(serialize_with = "serialize_some_other_variant")] #[serde(deserialize_with = "deserialize_some_other_variant")] #[allow(dead_code)] Tuple(String, u8), #[serde(serialize_with = "ser_x")] #[serde(deserialize_with = "de_x")] #[allow(dead_code)] Struct1 { x: X }, #[serde(serialize_with = "serialize_some_other_variant")] #[serde(deserialize_with = "deserialize_some_other_variant")] #[allow(dead_code)] Struct { f1: String, f2: u8 }, #[serde(serialize_with = "serialize_some_unit_variant")] #[serde(deserialize_with = "deserialize_some_unit_variant")] #[allow(dead_code)] Unit, } assert_ser::(); #[derive(Serialize, Deserialize)] #[serde(untagged)] enum UntaggedVariantWith { #[serde(serialize_with = "ser_x")] #[serde(deserialize_with = "de_x")] #[allow(dead_code)] Newtype(X), #[serde(serialize_with = "serialize_some_other_variant")] #[serde(deserialize_with = "deserialize_some_other_variant")] #[allow(dead_code)] Tuple(String, u8), #[serde(serialize_with = "ser_x")] #[serde(deserialize_with = "de_x")] #[allow(dead_code)] Struct1 { x: X }, #[serde(serialize_with = "serialize_some_other_variant")] #[serde(deserialize_with = "deserialize_some_other_variant")] #[allow(dead_code)] Struct { f1: String, f2: u8 }, #[serde(serialize_with = "serialize_some_unit_variant")] #[serde(deserialize_with = "deserialize_some_unit_variant")] #[allow(dead_code)] Unit, } assert_ser::(); #[derive(Serialize, Deserialize)] struct FlattenWith { #[serde(flatten, serialize_with = "ser_x", deserialize_with = "de_x")] x: X, } assert::(); #[derive(Serialize, Deserialize)] #[serde(deny_unknown_fields)] struct FlattenDenyUnknown { #[serde(flatten)] t: T, } #[derive(Serialize, Deserialize)] struct StaticStrStruct<'a> { a: &'a str, b: &'static str, } #[derive(Serialize, Deserialize)] struct StaticStrTupleStruct<'a>(&'a str, &'static str); #[derive(Serialize, Deserialize)] struct StaticStrNewtypeStruct(&'static str); #[derive(Serialize, Deserialize)] enum StaticStrEnum<'a> { Struct { a: &'a str, b: &'static str }, Tuple(&'a str, &'static str), Newtype(&'static str), } #[derive(Serialize, Deserialize)] struct SkippedStaticStr { #[serde(skip_deserializing)] skipped: &'static str, other: isize, } assert::(); macro_rules! T { () => { () }; } #[derive(Serialize, Deserialize)] struct TypeMacro { mac: T!(), marker: PhantomData, } assert::>(); #[derive(Serialize)] struct BigArray { #[serde(serialize_with = "<[_]>::serialize")] array: [u8; 256], } assert_ser::(); trait AssocSerde { type Assoc; } struct NoSerdeImpl; impl AssocSerde for NoSerdeImpl { type Assoc = u32; } #[derive(Serialize, Deserialize)] struct AssocDerive { assoc: T::Assoc, } assert::>(); #[derive(Serialize, Deserialize)] struct AssocDeriveMulti { s: S, assoc: T::Assoc, } assert::>(); #[derive(Serialize)] #[serde(tag = "t", content = "c")] enum EmptyAdjacentlyTagged { #[allow(dead_code)] Struct {}, #[allow(dead_code)] Tuple(), } assert_ser::(); mod restricted { mod inner { use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize)] struct Restricted { pub(super) a: usize, pub(in super::inner) b: usize, } } } #[derive(Deserialize)] #[serde(tag = "t", content = "c")] enum AdjacentlyTaggedVoid {} #[derive(Serialize, Deserialize)] enum SkippedVariant { #[serde(skip)] #[allow(dead_code)] T(T), Unit, } assert::>(); #[derive(Deserialize)] struct ImplicitlyBorrowedOption<'a> { option: std::option::Option<&'a str>, } #[derive(Serialize, Deserialize)] #[serde(untagged)] enum UntaggedNewtypeVariantWith { Newtype( #[serde(serialize_with = "ser_x")] #[serde(deserialize_with = "de_x")] X, ), } #[derive(Serialize, Deserialize)] #[serde(transparent)] struct TransparentWith { #[serde(serialize_with = "ser_x")] #[serde(deserialize_with = "de_x")] x: X, } #[derive(Deserialize)] #[serde(untagged)] enum UntaggedWithBorrow<'a> { Single(#[serde(borrow)] RelObject<'a>), Many(#[serde(borrow)] Vec>), } #[derive(Deserialize)] struct RelObject<'a> { ty: &'a str, id: String, } #[derive(Serialize, Deserialize)] struct FlattenSkipSerializing { #[serde(flatten, skip_serializing)] #[allow(dead_code)] flat: T, } #[derive(Serialize, Deserialize)] struct FlattenSkipSerializingIf { #[serde(flatten, skip_serializing_if = "StdOption::is_none")] flat: StdOption, } #[derive(Serialize, Deserialize)] struct FlattenSkipDeserializing { #[serde(flatten, skip_deserializing)] flat: T, } // https://github.com/serde-rs/serde/issues/1804 #[derive(Serialize, Deserialize)] enum Message { #[serde(skip)] #[allow(dead_code)] String(String), #[serde(other)] Unknown, } #[derive(Serialize)] #[repr(packed)] struct Packed { x: u8, y: u16, } macro_rules! deriving { ($field:ty) => { #[derive(Deserialize)] struct MacroRules<'a> { field: $field, } }; } deriving!(&'a str); macro_rules! mac { ($($tt:tt)*) => { $($tt)* }; } #[derive(Deserialize)] struct BorrowLifetimeInsideMacro<'a> { #[serde(borrow = "'a")] f: mac!(Cow<'a, str>), } #[derive(Serialize)] struct Struct { #[serde(serialize_with = "vec_first_element")] vec: Vec, } } ////////////////////////////////////////////////////////////////////////// fn assert() {} fn assert_ser() {} trait SerializeWith { fn serialize_with(_: &Self, _: S) -> StdResult; } trait DeserializeWith: Sized { fn deserialize_with<'de, D: Deserializer<'de>>(_: D) -> StdResult; } // Implements neither Serialize nor Deserialize pub struct X; pub fn ser_x(_: &X, _: S) -> StdResult { unimplemented!() } pub fn de_x<'de, D: Deserializer<'de>>(_: D) -> StdResult { unimplemented!() } mod both_x { pub use super::{de_x as deserialize, ser_x as serialize}; } impl SerializeWith for X { fn serialize_with(_: &Self, _: S) -> StdResult { unimplemented!() } } impl DeserializeWith for X { fn deserialize_with<'de, D: Deserializer<'de>>(_: D) -> StdResult { unimplemented!() } } pub fn serialize_some_unit_variant(_: S) -> StdResult where S: Serializer, { unimplemented!() } pub fn deserialize_some_unit_variant<'de, D>(_: D) -> StdResult<(), D::Error> where D: Deserializer<'de>, { unimplemented!() } pub fn serialize_some_other_variant(_: &str, _: &u8, _: S) -> StdResult where S: Serializer, { unimplemented!() } pub fn deserialize_some_other_variant<'de, D>(_: D) -> StdResult<(String, u8), D::Error> where D: Deserializer<'de>, { unimplemented!() } pub fn is_zero(n: &u8) -> bool { *n == 0 } fn vec_first_element(vec: &Vec, serializer: S) -> StdResult where T: Serialize, S: Serializer, { vec.first().serialize(serializer) } ////////////////////////////////////////////////////////////////////////// #[derive(Debug, PartialEq, Deserialize)] #[serde(tag = "tag")] enum InternallyTagged { #[serde(deserialize_with = "deserialize_generic")] Unit, #[serde(deserialize_with = "deserialize_generic")] Newtype(i32), #[serde(deserialize_with = "deserialize_generic")] Struct { f1: String, f2: u8 }, } fn deserialize_generic<'de, T, D>(deserializer: D) -> StdResult where T: Deserialize<'de>, D: Deserializer<'de>, { T::deserialize(deserializer) } ////////////////////////////////////////////////////////////////////////// #[repr(packed)] pub struct RemotePacked { pub a: u16, pub b: u32, } #[derive(Serialize)] #[repr(packed)] #[serde(remote = "RemotePacked")] pub struct RemotePackedDef { a: u16, b: u32, } impl Drop for RemotePackedDef { fn drop(&mut self) {} } #[repr(packed)] pub struct RemotePackedNonCopy { pub a: u16, pub b: String, } #[derive(Deserialize)] #[repr(packed)] #[serde(remote = "RemotePackedNonCopy")] pub struct RemotePackedNonCopyDef { a: u16, b: String, } impl Drop for RemotePackedNonCopyDef { fn drop(&mut self) {} } ////////////////////////////////////////////////////////////////////////// /// Regression tests for #[allow(dead_code)] mod static_and_flatten { use serde::Deserialize; #[derive(Deserialize)] struct Nested; #[derive(Deserialize)] enum ExternallyTagged { Flatten { #[serde(flatten)] nested: Nested, string: &'static str, }, } #[derive(Deserialize)] #[serde(tag = "tag")] enum InternallyTagged { Flatten { #[serde(flatten)] nested: Nested, string: &'static str, }, } #[derive(Deserialize)] #[serde(tag = "tag", content = "content")] enum AdjacentlyTagged { Flatten { #[serde(flatten)] nested: Nested, string: &'static str, }, } #[derive(Deserialize)] #[serde(untagged)] enum UntaggedWorkaround { Flatten { #[serde(flatten)] nested: Nested, string: &'static str, }, } }