mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-04-22 20:38:02 +00:00
Derive for remote types
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
use syn;
|
||||
use attr;
|
||||
use check;
|
||||
use Ctxt;
|
||||
|
||||
pub struct Item<'a> {
|
||||
@@ -62,12 +63,14 @@ impl<'a> Item<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
let item = Item {
|
||||
ident: item.ident.clone(),
|
||||
attrs: attrs,
|
||||
body: body,
|
||||
generics: &item.generics,
|
||||
}
|
||||
};
|
||||
check::check(cx, &item);
|
||||
item
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +84,10 @@ impl<'a> Body<'a> {
|
||||
Body::Struct(_, ref fields) => Box::new(fields.iter()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_getter(&self) -> bool {
|
||||
self.all_fields().any(|f| f.attrs.getter().is_some())
|
||||
}
|
||||
}
|
||||
|
||||
fn enum_from_ast<'a>(cx: &Ctxt, variants: &'a [syn::Variant]) -> Vec<Variant<'a>> {
|
||||
|
||||
@@ -102,6 +102,7 @@ pub struct Item {
|
||||
tag: EnumTag,
|
||||
from_type: Option<syn::Ty>,
|
||||
into_type: Option<syn::Ty>,
|
||||
remote: Option<syn::Path>,
|
||||
}
|
||||
|
||||
/// Styles of representing an enum.
|
||||
@@ -151,6 +152,7 @@ impl Item {
|
||||
let mut content = Attr::none(cx, "content");
|
||||
let mut from_type = Attr::none(cx, "from");
|
||||
let mut into_type = Attr::none(cx, "into");
|
||||
let mut remote = Attr::none(cx, "remote");
|
||||
|
||||
for meta_items in item.attrs.iter().filter_map(get_serde_meta_items) {
|
||||
for meta_item in meta_items {
|
||||
@@ -290,6 +292,13 @@ impl Item {
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(remote = "...")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "remote" => {
|
||||
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
||||
remote.set(path);
|
||||
}
|
||||
}
|
||||
|
||||
MetaItem(ref meta_item) => {
|
||||
cx.error(format!("unknown serde container attribute `{}`",
|
||||
meta_item.name()));
|
||||
@@ -361,6 +370,7 @@ impl Item {
|
||||
tag: tag,
|
||||
from_type: from_type.get(),
|
||||
into_type: into_type.get(),
|
||||
remote: remote.get(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -399,6 +409,10 @@ impl Item {
|
||||
pub fn into_type(&self) -> Option<&syn::Ty> {
|
||||
self.into_type.as_ref()
|
||||
}
|
||||
|
||||
pub fn remote(&self) -> Option<&syn::Path> {
|
||||
self.remote.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents variant attribute information
|
||||
@@ -531,6 +545,7 @@ pub struct Field {
|
||||
ser_bound: Option<Vec<syn::WherePredicate>>,
|
||||
de_bound: Option<Vec<syn::WherePredicate>>,
|
||||
borrowed_lifetimes: BTreeSet<syn::Lifetime>,
|
||||
getter: Option<syn::Path>,
|
||||
}
|
||||
|
||||
/// Represents the default to use for a field when deserializing.
|
||||
@@ -558,6 +573,7 @@ impl Field {
|
||||
let mut ser_bound = Attr::none(cx, "bound");
|
||||
let mut de_bound = Attr::none(cx, "bound");
|
||||
let mut borrowed_lifetimes = Attr::none(cx, "borrow");
|
||||
let mut getter = Attr::none(cx, "getter");
|
||||
|
||||
let ident = match field.ident {
|
||||
Some(ref ident) => ident.to_string(),
|
||||
@@ -676,6 +692,13 @@ impl Field {
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(getter = "...")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "getter" => {
|
||||
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
||||
getter.set(path);
|
||||
}
|
||||
}
|
||||
|
||||
MetaItem(ref meta_item) => {
|
||||
cx.error(format!("unknown serde field attribute `{}`", meta_item.name()));
|
||||
}
|
||||
@@ -737,6 +760,7 @@ impl Field {
|
||||
ser_bound: ser_bound.get(),
|
||||
de_bound: de_bound.get(),
|
||||
borrowed_lifetimes: borrowed_lifetimes,
|
||||
getter: getter.get(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -788,6 +812,10 @@ impl Field {
|
||||
pub fn borrowed_lifetimes(&self) -> &BTreeSet<syn::Lifetime> {
|
||||
&self.borrowed_lifetimes
|
||||
}
|
||||
|
||||
pub fn getter(&self) -> Option<&syn::Path> {
|
||||
self.getter.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
type SerAndDe<T> = (Option<T>, Option<T>);
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
use ast::{Body, Item};
|
||||
use Ctxt;
|
||||
|
||||
/// Cross-cutting checks that require looking at more than a single attrs
|
||||
/// object. Simpler checks should happen when parsing and building the attrs.
|
||||
pub fn check(cx: &Ctxt, item: &Item) {
|
||||
match item.body {
|
||||
Body::Enum(_) => {
|
||||
if item.body.has_getter() {
|
||||
cx.error("#[serde(getter = \"...\")] is not allowed in an enum");
|
||||
}
|
||||
}
|
||||
Body::Struct(_, _) => {
|
||||
if item.body.has_getter() && item.attrs.remote().is_none() {
|
||||
cx.error("#[serde(getter = \"...\")] can only be used in structs \
|
||||
that have #[serde(remote = \"...\")]");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,3 +9,4 @@ mod ctxt;
|
||||
pub use ctxt::Ctxt;
|
||||
|
||||
mod case;
|
||||
mod check;
|
||||
|
||||
Reference in New Issue
Block a user