mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-06-15 13:11:01 +00:00
Revamp serde_codegen_internals error handling
This commit is contained in:
@@ -5,11 +5,12 @@ use bound;
|
|||||||
use internals::ast::{Body, Field, Item, Style, Variant};
|
use internals::ast::{Body, Field, Item, Style, Variant};
|
||||||
use internals::{self, attr};
|
use internals::{self, attr};
|
||||||
|
|
||||||
pub fn expand_derive_deserialize(item: &syn::MacroInput) -> Tokens {
|
pub fn expand_derive_deserialize(item: &syn::MacroInput) -> Result<Tokens, String> {
|
||||||
let item = {
|
let item = {
|
||||||
let ctxt = internals::Ctxt::new();
|
let ctxt = internals::Ctxt::new();
|
||||||
let item = Item::from_ast(&ctxt, item);
|
let item = Item::from_ast(&ctxt, item);
|
||||||
check_no_str(&ctxt, &item);
|
check_no_str(&ctxt, &item);
|
||||||
|
try!(ctxt.check());
|
||||||
item
|
item
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ pub fn expand_derive_deserialize(item: &syn::MacroInput) -> Tokens {
|
|||||||
|
|
||||||
let dummy_const = aster::id(format!("_IMPL_DESERIALIZE_FOR_{}", item.ident));
|
let dummy_const = aster::id(format!("_IMPL_DESERIALIZE_FOR_{}", item.ident));
|
||||||
|
|
||||||
quote! {
|
Ok(quote! {
|
||||||
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
|
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
|
||||||
const #dummy_const: () = {
|
const #dummy_const: () = {
|
||||||
extern crate serde as _serde;
|
extern crate serde as _serde;
|
||||||
@@ -40,7 +41,7 @@ pub fn expand_derive_deserialize(item: &syn::MacroInput) -> Tokens {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// All the generics in the input, plus a bound `T: Deserialize` for each generic
|
// All the generics in the input, plus a bound `T: Deserialize` for each generic
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ macro_rules! shim {
|
|||||||
($name:ident $pkg:ident :: $func:ident) => {
|
($name:ident $pkg:ident :: $func:ident) => {
|
||||||
fn $func(
|
fn $func(
|
||||||
cx: &mut ::syntax::ext::base::ExtCtxt,
|
cx: &mut ::syntax::ext::base::ExtCtxt,
|
||||||
_span: ::syntax::codemap::Span,
|
span: ::syntax::codemap::Span,
|
||||||
meta_item: &::syntax::ast::MetaItem,
|
meta_item: &::syntax::ast::MetaItem,
|
||||||
annotatable: &::syntax::ext::base::Annotatable,
|
annotatable: &::syntax::ext::base::Annotatable,
|
||||||
push: &mut FnMut(::syntax::ext::base::Annotatable)
|
push: &mut FnMut(::syntax::ext::base::Annotatable)
|
||||||
@@ -158,7 +158,13 @@ macro_rules! shim {
|
|||||||
let s = pprust::item_to_string(item);
|
let s = pprust::item_to_string(item);
|
||||||
|
|
||||||
let syn_item = syn::parse_macro_input(&s).unwrap();
|
let syn_item = syn::parse_macro_input(&s).unwrap();
|
||||||
let expanded = $pkg::$func(&syn_item).to_string();
|
let expanded = match $pkg::$func(&syn_item) {
|
||||||
|
Ok(expanded) => expanded.to_string(),
|
||||||
|
Err(msg) => {
|
||||||
|
cx.span_err(span, &msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
use syntax::parse;
|
use syntax::parse;
|
||||||
let name = stringify!($name).to_string();
|
let name = stringify!($name).to_string();
|
||||||
@@ -174,21 +180,21 @@ shim!(Serialize ser::expand_derive_serialize);
|
|||||||
shim!(Deserialize de::expand_derive_deserialize);
|
shim!(Deserialize de::expand_derive_deserialize);
|
||||||
|
|
||||||
#[cfg(feature = "with-syn")]
|
#[cfg(feature = "with-syn")]
|
||||||
pub fn expand_single_item(item: &str) -> String {
|
pub fn expand_single_item(item: &str) -> Result<String, String> {
|
||||||
let syn_item = syn::parse_macro_input(item).unwrap();
|
let syn_item = syn::parse_macro_input(item).unwrap();
|
||||||
let (ser, de, syn_item) = strip_serde_derives(syn_item);
|
let (ser, de, syn_item) = strip_serde_derives(syn_item);
|
||||||
let expanded_ser = if ser {
|
let expanded_ser = if ser {
|
||||||
Some(ser::expand_derive_serialize(&syn_item))
|
Some(try!(ser::expand_derive_serialize(&syn_item)))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let expanded_de = if de {
|
let expanded_de = if de {
|
||||||
Some(de::expand_derive_deserialize(&syn_item))
|
Some(try!(de::expand_derive_deserialize(&syn_item)))
|
||||||
} else {
|
} else {
|
||||||
None::<quote::Tokens>
|
None::<quote::Tokens>
|
||||||
};
|
};
|
||||||
let syn_item = strip_serde_attrs(syn_item);
|
let syn_item = strip_serde_attrs(syn_item);
|
||||||
return quote!(#expanded_ser #expanded_de #syn_item).to_string();
|
return Ok(quote!(#expanded_ser #expanded_de #syn_item).to_string());
|
||||||
|
|
||||||
fn strip_serde_derives(item: syn::MacroInput) -> (bool, bool, syn::MacroInput) {
|
fn strip_serde_derives(item: syn::MacroInput) -> (bool, bool, syn::MacroInput) {
|
||||||
let mut ser = false;
|
let mut ser = false;
|
||||||
|
|||||||
@@ -5,8 +5,10 @@ use bound;
|
|||||||
use internals::ast::{Body, Field, Item, Style, Variant};
|
use internals::ast::{Body, Field, Item, Style, Variant};
|
||||||
use internals::{self, attr};
|
use internals::{self, attr};
|
||||||
|
|
||||||
pub fn expand_derive_serialize(item: &syn::MacroInput) -> Tokens {
|
pub fn expand_derive_serialize(item: &syn::MacroInput) -> Result<Tokens, String> {
|
||||||
let item = Item::from_ast(&internals::Ctxt::new(), item);
|
let ctxt = internals::Ctxt::new();
|
||||||
|
let item = Item::from_ast(&ctxt, item);
|
||||||
|
try!(ctxt.check());
|
||||||
|
|
||||||
let impl_generics = build_impl_generics(&item);
|
let impl_generics = build_impl_generics(&item);
|
||||||
|
|
||||||
@@ -22,7 +24,7 @@ pub fn expand_derive_serialize(item: &syn::MacroInput) -> Tokens {
|
|||||||
|
|
||||||
let dummy_const = aster::id(format!("_IMPL_SERIALIZE_FOR_{}", item.ident));
|
let dummy_const = aster::id(format!("_IMPL_SERIALIZE_FOR_{}", item.ident));
|
||||||
|
|
||||||
quote! {
|
Ok(quote! {
|
||||||
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
|
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
|
||||||
const #dummy_const: () = {
|
const #dummy_const: () = {
|
||||||
extern crate serde as _serde;
|
extern crate serde as _serde;
|
||||||
@@ -35,7 +37,7 @@ pub fn expand_derive_serialize(item: &syn::MacroInput) -> Tokens {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// All the generics in the input, plus a bound `T: Serialize` for each generic
|
// All the generics in the input, plus a bound `T: Serialize` for each generic
|
||||||
|
|||||||
@@ -1,29 +1,43 @@
|
|||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::cell::Cell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Ctxt {
|
pub struct Ctxt {
|
||||||
err_count: Cell<usize>,
|
errors: RefCell<Option<Vec<String>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ctxt {
|
impl Ctxt {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Default::default()
|
Ctxt {
|
||||||
|
errors: RefCell::new(Some(Vec::new())),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn error<T: Display>(&self, msg: T) {
|
pub fn error<T: Display>(&self, msg: T) {
|
||||||
println!("{}", msg);
|
self.errors.borrow_mut().as_mut().unwrap().push(msg.to_string());
|
||||||
self.err_count.set(self.err_count.get() + 1);
|
}
|
||||||
|
|
||||||
|
pub fn check(self) -> Result<(), String> {
|
||||||
|
let mut errors = self.errors.borrow_mut().take().unwrap();
|
||||||
|
match errors.len() {
|
||||||
|
0 => Ok(()),
|
||||||
|
1 => Err(errors.pop().unwrap()),
|
||||||
|
n => {
|
||||||
|
let mut msg = format!("{} errors:", n);
|
||||||
|
for err in errors {
|
||||||
|
msg += "\n\t# ";
|
||||||
|
msg += &err;
|
||||||
|
}
|
||||||
|
Err(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Ctxt {
|
impl Drop for Ctxt {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let err_count = self.err_count.get();
|
if self.errors.borrow().is_some() {
|
||||||
if err_count == 1 {
|
panic!("forgot to check for errors");
|
||||||
panic!("1 error");
|
|
||||||
} else if err_count > 1 {
|
|
||||||
panic!("{} errors", err_count);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,13 +9,17 @@ use rustc_macro::TokenStream;
|
|||||||
#[rustc_macro_derive(Serialize)]
|
#[rustc_macro_derive(Serialize)]
|
||||||
pub fn derive_serialize(input: TokenStream) -> TokenStream {
|
pub fn derive_serialize(input: TokenStream) -> TokenStream {
|
||||||
let item = format!("#[derive(Serialize)]\n{}", input);
|
let item = format!("#[derive(Serialize)]\n{}", input);
|
||||||
let expanded = serde_codegen::expand_single_item(&item);
|
match serde_codegen::expand_single_item(&item) {
|
||||||
expanded.parse().unwrap()
|
Ok(expanded) => expanded.parse().unwrap(),
|
||||||
|
Err(msg) => panic!(msg),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustc_macro_derive(Deserialize)]
|
#[rustc_macro_derive(Deserialize)]
|
||||||
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
|
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
|
||||||
let item = format!("#[derive(Deserialize)]\n{}", input);
|
let item = format!("#[derive(Deserialize)]\n{}", input);
|
||||||
let expanded = serde_codegen::expand_single_item(&item);
|
match serde_codegen::expand_single_item(&item) {
|
||||||
expanded.parse().unwrap()
|
Ok(expanded) => expanded.parse().unwrap(),
|
||||||
|
Err(msg) => panic!(msg),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user