mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-07-04 19:07:22 +00:00
Allow #[serde(serde_path = "...")] to override extern crate serde
This is intended to be used by other crates which provide their own proc macros and use serde internally. Today there's no consistent way to put `#[derive(Deserialize)]` on a struct that consistently works, since crates may be using either `features = ["derive"]` or relying on `serde_derive` separately. Even if we assume that everyone is using `features = ["derive"]`, without this commit, any crate which generates `#[derive(serde::Deserialize)]` forces its consumers to put `serde` in their `Cargo.toml`, even if they aren't otherwise using serde for anything. Examples of crates which suffer from this in the real world are tower-web and swirl. With this feature, it's expected that these crates would have `pub extern crate serde;` in some accessible path, and add `#[serde(serde_path = "that_crate::wherever::serde")]` anywhere they place serde's derives. Those crates would also have to derive `that_crate::whatever::serde::Deserialize`, or `use` the macros explicitly beforehand. The test for this is a little funky, as it's testing this in a way that is not the intended use case, or even one we want to support. It has its own module which re-exports all of serde, but defines its own `Serialize` and `Deserialize` traits. We then test that we generated impls for those traits, instead of serde's. The only other way to test this would be to create a new test crate which does not depend on serde, but instead depends on `serde_derive` and a third crate which publicly re-exports serde. This feels like way too much overhead for a single test case, hence the funky test given. I didn't see anywhere in this repo to document this attribute, so I assume the docs will have to be done as a separate PR to a separate repo. Fixes #1487
This commit is contained in:
@@ -2,7 +2,7 @@ use proc_macro2::{Ident, Span, TokenStream};
|
||||
|
||||
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 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
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user