mirror of
https://github.com/serde-rs/serde.git
synced 2025-10-02 15:25:38 +00:00
Merge pull request #1499 from sgrif/sg-custom-serde-path
Allow `#[serde(crate = "...")]` to override `extern crate serde`
This commit is contained in:
commit
465392b618
@ -27,15 +27,16 @@ pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<TokenStream
|
|||||||
let (de_impl_generics, _, ty_generics, where_clause) = split_with_de_lifetime(¶ms);
|
let (de_impl_generics, _, ty_generics, where_clause) = split_with_de_lifetime(¶ms);
|
||||||
let body = Stmts(deserialize_body(&cont, ¶ms));
|
let body = Stmts(deserialize_body(&cont, ¶ms));
|
||||||
let delife = params.borrowed.de_lifetime();
|
let delife = params.borrowed.de_lifetime();
|
||||||
|
let serde = cont.attrs.serde_path();
|
||||||
|
|
||||||
let impl_block = if let Some(remote) = cont.attrs.remote() {
|
let impl_block = if let Some(remote) = cont.attrs.remote() {
|
||||||
let vis = &input.vis;
|
let vis = &input.vis;
|
||||||
let used = pretend::pretend_used(&cont);
|
let used = pretend::pretend_used(&cont);
|
||||||
quote! {
|
quote! {
|
||||||
impl #de_impl_generics #ident #ty_generics #where_clause {
|
impl #de_impl_generics #ident #ty_generics #where_clause {
|
||||||
#vis fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<#remote #ty_generics, __D::Error>
|
#vis fn deserialize<__D>(__deserializer: __D) -> #serde::export::Result<#remote #ty_generics, __D::Error>
|
||||||
where
|
where
|
||||||
__D: _serde::Deserializer<#delife>,
|
__D: #serde::Deserializer<#delife>,
|
||||||
{
|
{
|
||||||
#used
|
#used
|
||||||
#body
|
#body
|
||||||
@ -47,10 +48,10 @@ pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<TokenStream
|
|||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
impl #de_impl_generics _serde::Deserialize<#delife> for #ident #ty_generics #where_clause {
|
impl #de_impl_generics #serde::Deserialize<#delife> for #ident #ty_generics #where_clause {
|
||||||
fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<Self, __D::Error>
|
fn deserialize<__D>(__deserializer: __D) -> #serde::export::Result<Self, __D::Error>
|
||||||
where
|
where
|
||||||
__D: _serde::Deserializer<#delife>,
|
__D: #serde::Deserializer<#delife>,
|
||||||
{
|
{
|
||||||
#body
|
#body
|
||||||
}
|
}
|
||||||
@ -60,7 +61,7 @@ pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<TokenStream
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(dummy::wrap_in_const("DESERIALIZE", ident, impl_block))
|
Ok(dummy::wrap_in_const(cont.attrs.custom_serde_path(), "DESERIALIZE", ident, impl_block))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn precondition(cx: &Ctxt, cont: &Container) {
|
fn precondition(cx: &Ctxt, cont: &Container) {
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use proc_macro2::{Ident, Span, TokenStream};
|
use proc_macro2::{Ident, Span, TokenStream};
|
||||||
|
|
||||||
|
use syn;
|
||||||
use try;
|
use try;
|
||||||
|
|
||||||
pub fn wrap_in_const(trait_: &str, ty: &Ident, code: TokenStream) -> TokenStream {
|
pub fn wrap_in_const(serde_path: Option<&syn::Path>, trait_: &str, ty: &Ident, code: TokenStream) -> TokenStream {
|
||||||
let try_replacement = try::replacement();
|
let try_replacement = try::replacement();
|
||||||
|
|
||||||
let dummy_const = Ident::new(
|
let dummy_const = Ident::new(
|
||||||
@ -10,13 +11,21 @@ pub fn wrap_in_const(trait_: &str, ty: &Ident, code: TokenStream) -> TokenStream
|
|||||||
Span::call_site(),
|
Span::call_site(),
|
||||||
);
|
);
|
||||||
|
|
||||||
quote! {
|
let use_serde = serde_path.map(|path| {
|
||||||
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
|
quote!(use #path as _serde;)
|
||||||
const #dummy_const: () = {
|
}).unwrap_or_else(|| {
|
||||||
|
quote! {
|
||||||
#[allow(unknown_lints)]
|
#[allow(unknown_lints)]
|
||||||
#[cfg_attr(feature = "cargo-clippy", allow(useless_attribute))]
|
#[cfg_attr(feature = "cargo-clippy", allow(useless_attribute))]
|
||||||
#[allow(rust_2018_idioms)]
|
#[allow(rust_2018_idioms)]
|
||||||
extern crate serde as _serde;
|
extern crate serde as _serde;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
|
||||||
|
const #dummy_const: () = {
|
||||||
|
#use_serde
|
||||||
#try_replacement
|
#try_replacement
|
||||||
#code
|
#code
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use internals::Ctxt;
|
use internals::Ctxt;
|
||||||
use proc_macro2::{Group, Span, TokenStream, TokenTree};
|
use proc_macro2::{Group, Span, TokenStream, TokenTree};
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use syn;
|
use syn;
|
||||||
@ -218,6 +219,7 @@ pub struct Container {
|
|||||||
remote: Option<syn::Path>,
|
remote: Option<syn::Path>,
|
||||||
identifier: Identifier,
|
identifier: Identifier,
|
||||||
has_flatten: bool,
|
has_flatten: bool,
|
||||||
|
serde_path: Option<syn::Path>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Styles of representing an enum.
|
/// Styles of representing an enum.
|
||||||
@ -298,6 +300,7 @@ impl Container {
|
|||||||
let mut remote = Attr::none(cx, "remote");
|
let mut remote = Attr::none(cx, "remote");
|
||||||
let mut field_identifier = BoolAttr::none(cx, "field_identifier");
|
let mut field_identifier = BoolAttr::none(cx, "field_identifier");
|
||||||
let mut variant_identifier = BoolAttr::none(cx, "variant_identifier");
|
let mut variant_identifier = BoolAttr::none(cx, "variant_identifier");
|
||||||
|
let mut serde_path = Attr::none(cx, "crate");
|
||||||
|
|
||||||
for meta_items in item.attrs.iter().filter_map(get_serde_meta_items) {
|
for meta_items in item.attrs.iter().filter_map(get_serde_meta_items) {
|
||||||
for meta_item in meta_items {
|
for meta_item in meta_items {
|
||||||
@ -582,6 +585,13 @@ impl Container {
|
|||||||
variant_identifier.set_true(word);
|
variant_identifier.set_true(word);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse `#[serde(crate = "foo")]`
|
||||||
|
Meta(NameValue(ref m)) if m.ident == "crate" => {
|
||||||
|
if let Ok(path) = parse_lit_into_path(cx, &m.ident, &m.lit) {
|
||||||
|
serde_path.set(&m.ident, path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Meta(ref meta_item) => {
|
Meta(ref meta_item) => {
|
||||||
cx.error_spanned_by(
|
cx.error_spanned_by(
|
||||||
meta_item.name(),
|
meta_item.name(),
|
||||||
@ -613,6 +623,7 @@ impl Container {
|
|||||||
remote: remote.get(),
|
remote: remote.get(),
|
||||||
identifier: decide_identifier(cx, item, field_identifier, variant_identifier),
|
identifier: decide_identifier(cx, item, field_identifier, variant_identifier),
|
||||||
has_flatten: false,
|
has_flatten: false,
|
||||||
|
serde_path: serde_path.get(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -671,6 +682,16 @@ impl Container {
|
|||||||
pub fn mark_has_flatten(&mut self) {
|
pub fn mark_has_flatten(&mut self) {
|
||||||
self.has_flatten = true;
|
self.has_flatten = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn custom_serde_path(&self) -> Option<&syn::Path> {
|
||||||
|
self.serde_path.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn serde_path(&self) -> Cow<syn::Path> {
|
||||||
|
self.custom_serde_path()
|
||||||
|
.map(Cow::Borrowed)
|
||||||
|
.unwrap_or_else(|| Cow::Owned(parse_quote!(_serde)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decide_tag(
|
fn decide_tag(
|
||||||
|
@ -22,15 +22,16 @@ pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<TokenStream,
|
|||||||
let params = Parameters::new(&cont);
|
let params = Parameters::new(&cont);
|
||||||
let (impl_generics, ty_generics, where_clause) = params.generics.split_for_impl();
|
let (impl_generics, ty_generics, where_clause) = params.generics.split_for_impl();
|
||||||
let body = Stmts(serialize_body(&cont, ¶ms));
|
let body = Stmts(serialize_body(&cont, ¶ms));
|
||||||
|
let serde = cont.attrs.serde_path();
|
||||||
|
|
||||||
let impl_block = if let Some(remote) = cont.attrs.remote() {
|
let impl_block = if let Some(remote) = cont.attrs.remote() {
|
||||||
let vis = &input.vis;
|
let vis = &input.vis;
|
||||||
let used = pretend::pretend_used(&cont);
|
let used = pretend::pretend_used(&cont);
|
||||||
quote! {
|
quote! {
|
||||||
impl #impl_generics #ident #ty_generics #where_clause {
|
impl #impl_generics #ident #ty_generics #where_clause {
|
||||||
#vis fn serialize<__S>(__self: &#remote #ty_generics, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error>
|
#vis fn serialize<__S>(__self: &#remote #ty_generics, __serializer: __S) -> #serde::export::Result<__S::Ok, __S::Error>
|
||||||
where
|
where
|
||||||
__S: _serde::Serializer,
|
__S: #serde::Serializer,
|
||||||
{
|
{
|
||||||
#used
|
#used
|
||||||
#body
|
#body
|
||||||
@ -40,10 +41,10 @@ pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<TokenStream,
|
|||||||
} else {
|
} else {
|
||||||
quote! {
|
quote! {
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
impl #impl_generics _serde::Serialize for #ident #ty_generics #where_clause {
|
impl #impl_generics #serde::Serialize for #ident #ty_generics #where_clause {
|
||||||
fn serialize<__S>(&self, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error>
|
fn serialize<__S>(&self, __serializer: __S) -> #serde::export::Result<__S::Ok, __S::Error>
|
||||||
where
|
where
|
||||||
__S: _serde::Serializer,
|
__S: #serde::Serializer,
|
||||||
{
|
{
|
||||||
#body
|
#body
|
||||||
}
|
}
|
||||||
@ -51,7 +52,7 @@ pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<TokenStream,
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(dummy::wrap_in_const("SERIALIZE", ident, impl_block))
|
Ok(dummy::wrap_in_const(cont.attrs.custom_serde_path(), "SERIALIZE", ident, impl_block))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn precondition(cx: &Ctxt, cont: &Container) {
|
fn precondition(cx: &Ctxt, cont: &Container) {
|
||||||
|
39
test_suite/tests/test_serde_path.rs
Normal file
39
test_suite/tests/test_serde_path.rs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#[test]
|
||||||
|
fn test_gen_custom_serde() {
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(crate = "fake_serde")]
|
||||||
|
struct Foo;
|
||||||
|
|
||||||
|
// Would be overlapping if serde::Serialize were implemented
|
||||||
|
impl AssertNotSerdeSerialize for Foo {}
|
||||||
|
// Would be overlapping if serde::Deserialize were implemented
|
||||||
|
impl<'a> AssertNotSerdeDeserialize<'a> for Foo {}
|
||||||
|
|
||||||
|
fake_serde::assert::<Foo>();
|
||||||
|
}
|
||||||
|
|
||||||
|
mod fake_serde {
|
||||||
|
pub use serde::*;
|
||||||
|
|
||||||
|
pub fn assert<T>()
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
T: for<'a> Deserialize<'a>,
|
||||||
|
{}
|
||||||
|
|
||||||
|
pub trait Serialize {
|
||||||
|
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Deserialize<'a>: Sized {
|
||||||
|
fn deserialize<D: Deserializer<'a>>(deserializer: D) -> Result<Self, D::Error>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait AssertNotSerdeSerialize {}
|
||||||
|
|
||||||
|
impl<T: serde::Serialize> AssertNotSerdeSerialize for T {}
|
||||||
|
|
||||||
|
trait AssertNotSerdeDeserialize<'a> {}
|
||||||
|
|
||||||
|
impl<'a, T: serde::Deserialize<'a>> AssertNotSerdeDeserialize<'a> for T {}
|
Loading…
x
Reference in New Issue
Block a user