diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 7fa1030b..7e94ef25 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -60,7 +60,7 @@ pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result TokenStream { +pub fn wrap_in_const(serde_path: Option<&syn::Path>, trait_: &str, ty: &Ident, code: TokenStream) -> TokenStream { let try_replacement = try::replacement(); let dummy_const = Ident::new( @@ -10,13 +10,21 @@ pub fn wrap_in_const(trait_: &str, ty: &Ident, code: TokenStream) -> TokenStream Span::call_site(), ); - quote! { - #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] - const #dummy_const: () = { + let use_serde = serde_path.map(|path| { + quote!(use #path as _serde;) + }).unwrap_or_else(|| { + quote! { #[allow(unknown_lints)] #[cfg_attr(feature = "cargo-clippy", allow(useless_attribute))] #[allow(rust_2018_idioms)] extern crate serde as _serde; + } + }); + + quote! { + #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] + const #dummy_const: () = { + #use_serde #try_replacement #code }; diff --git a/serde_derive/src/internals/attr.rs b/serde_derive/src/internals/attr.rs index b95d490f..8bc91bbb 100644 --- a/serde_derive/src/internals/attr.rs +++ b/serde_derive/src/internals/attr.rs @@ -218,6 +218,7 @@ pub struct Container { remote: Option, identifier: Identifier, has_flatten: bool, + serde_path: Option, } /// Styles of representing an enum. @@ -298,6 +299,7 @@ impl Container { let mut remote = Attr::none(cx, "remote"); let mut field_identifier = BoolAttr::none(cx, "field_identifier"); let mut variant_identifier = BoolAttr::none(cx, "variant_identifier"); + let mut serde_path = Attr::none(cx, "serde_path"); for meta_items in item.attrs.iter().filter_map(get_serde_meta_items) { for meta_item in meta_items { @@ -582,6 +584,13 @@ impl Container { variant_identifier.set_true(word); } + // Parse `#[serde(serde_path = "foo")]` + Meta(NameValue(ref m)) if m.ident == "serde_path" => { + if let Ok(path) = parse_lit_into_path(cx, &m.ident, &m.lit) { + serde_path.set(&m.ident, path) + } + } + Meta(ref meta_item) => { cx.error_spanned_by( meta_item.name(), @@ -613,6 +622,7 @@ impl Container { remote: remote.get(), identifier: decide_identifier(cx, item, field_identifier, variant_identifier), has_flatten: false, + serde_path: serde_path.get(), } } @@ -671,6 +681,10 @@ impl Container { pub fn mark_has_flatten(&mut self) { self.has_flatten = true; } + + pub fn serde_path(&self) -> Option<&syn::Path> { + self.serde_path.as_ref() + } } fn decide_tag( diff --git a/serde_derive/src/ser.rs b/serde_derive/src/ser.rs index 4d1f680d..8f3e357c 100644 --- a/serde_derive/src/ser.rs +++ b/serde_derive/src/ser.rs @@ -51,7 +51,7 @@ pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result AssertNotSerdeDeserialize<'a> for Foo {} + + fake_serde::assert::(); +} + +mod fake_serde { + pub use serde::*; + + pub fn assert() + where + T: Serialize, + T: for<'a> Deserialize<'a>, + {} + + pub trait Serialize { + fn serialize(&self, serializer: S) -> Result; + } + + pub trait Deserialize<'a>: Sized { + fn deserialize>(deserializer: D) -> Result; + } +} + +trait AssertNotSerdeSerialize {} + +impl AssertNotSerdeSerialize for T {} + +trait AssertNotSerdeDeserialize<'a> {} + +impl<'a, T: serde::Deserialize<'a>> AssertNotSerdeDeserialize<'a> for T {}