mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-06-12 02:41:04 +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:
@@ -218,6 +218,7 @@ pub struct Container {
|
||||
remote: Option<syn::Path>,
|
||||
identifier: Identifier,
|
||||
has_flatten: bool,
|
||||
serde_path: Option<syn::Path>,
|
||||
}
|
||||
|
||||
/// 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(
|
||||
|
||||
Reference in New Issue
Block a user