1diff --git a/Cargo.toml b/Cargo.toml 2index 2e33871..388f042 100644 3--- a/Cargo.toml 4+++ b/Cargo.toml 5@@ -24,8 +24,6 @@ repository = "https://git.sr.ht/~ireas/merge-rs/tree/master/merge_derive" 6 7 [lib] 8 proc-macro = true 9-[dependencies.proc-macro-error] 10-version = "1.0" 11 12 [dependencies.proc-macro2] 13 version = "1.0" 14@@ -34,4 +32,4 @@ version = "1.0" 15 version = "1.0" 16 17 [dependencies.syn] 18-version = "1.0" 19+version = "2.0" 20diff --git a/src/lib.rs b/src/lib.rs 21index 75732f9..11f5b49 100644 22--- a/src/lib.rs 23+++ b/src/lib.rs 24@@ -11,9 +11,9 @@ 25 extern crate proc_macro; 26 27 use proc_macro2::TokenStream; 28-use proc_macro_error::{abort, abort_call_site, dummy::set_dummy, proc_macro_error, ResultExt}; 29 use quote::{quote, quote_spanned}; 30-use syn::Token; 31+use std::convert::TryFrom; 32+use syn::{Error, Result, Token}; 33 34 struct Field { 35 name: syn::Member, 36@@ -33,48 +33,51 @@ enum FieldAttr { 37 } 38 39 #[proc_macro_derive(Merge, attributes(merge))] 40-#[proc_macro_error] 41 pub fn merge_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { 42 let ast = syn::parse(input).unwrap(); 43- impl_merge(&ast).into() 44+ impl_merge(&ast) 45+ .unwrap_or_else(Error::into_compile_error) 46+ .into() 47 } 48 49-fn impl_merge(ast: &syn::DeriveInput) -> TokenStream { 50+fn impl_merge(ast: &syn::DeriveInput) -> Result<TokenStream> { 51 let name = &ast.ident; 52 53- set_dummy(quote! { 54- impl ::merge::Merge for #name { 55- fn merge(&mut self, other: Self) { 56- unimplemented!() 57- } 58- } 59- }); 60- 61 if let syn::Data::Struct(syn::DataStruct { ref fields, .. }) = ast.data { 62 impl_merge_for_struct(name, fields) 63 } else { 64- abort_call_site!("merge::Merge can only be derived for structs") 65+ Err(Error::new_spanned( 66+ ast, 67+ "merge::Merge can only be derived for structs", 68+ )) 69 } 70 } 71 72-fn impl_merge_for_struct(name: &syn::Ident, fields: &syn::Fields) -> TokenStream { 73- let assignments = gen_assignments(fields); 74+fn impl_merge_for_struct(name: &syn::Ident, fields: &syn::Fields) -> Result<TokenStream> { 75+ let assignments = gen_assignments(fields)?; 76 77- quote! { 78+ Ok(quote! { 79 impl ::merge::Merge for #name { 80 fn merge(&mut self, other: Self) { 81 #assignments 82 } 83 } 84- } 85+ }) 86 } 87 88-fn gen_assignments(fields: &syn::Fields) -> TokenStream { 89- let fields = fields.iter().enumerate().map(Field::from); 90- let assignments = fields.filter(|f| !f.attrs.skip).map(|f| gen_assignment(&f)); 91- quote! { 92+fn gen_assignments(fields: &syn::Fields) -> Result<TokenStream> { 93+ let fields = fields 94+ .iter() 95+ .enumerate() 96+ .map(Field::try_from) 97+ .collect::<Result<Vec<_>>>()?; 98+ let assignments = fields 99+ .iter() 100+ .filter(|f| !f.attrs.skip) 101+ .map(|f| gen_assignment(&f)); 102+ Ok(quote! { 103 #( #assignments )* 104- } 105+ }) 106 } 107 108 fn gen_assignment(field: &Field) -> TokenStream { 109@@ -88,48 +91,48 @@ fn gen_assignment(field: &Field) -> TokenStream { 110 } 111 } 112 113-impl From<(usize, &syn::Field)> for Field { 114- fn from(data: (usize, &syn::Field)) -> Self { 115+impl TryFrom<(usize, &syn::Field)> for Field { 116+ type Error = syn::Error; 117+ 118+ fn try_from(data: (usize, &syn::Field)) -> std::result::Result<Self, Self::Error> { 119 use syn::spanned::Spanned; 120 121 let (index, field) = data; 122- Field { 123+ Ok(Field { 124 name: if let Some(ident) = &field.ident { 125 syn::Member::Named(ident.clone()) 126 } else { 127 syn::Member::Unnamed(index.into()) 128 }, 129 span: field.span(), 130- attrs: field.attrs.iter().into(), 131- } 132+ attrs: FieldAttrs::new(field.attrs.iter())?, 133+ }) 134 } 135 } 136 137 impl FieldAttrs { 138- fn apply(&mut self, attr: FieldAttr) { 139- match attr { 140- FieldAttr::Skip => self.skip = true, 141- FieldAttr::Strategy(path) => self.strategy = Some(path), 142- } 143- } 144-} 145- 146-impl<'a, I: Iterator<Item = &'a syn::Attribute>> From<I> for FieldAttrs { 147- fn from(iter: I) -> Self { 148+ fn new<'a, I: Iterator<Item = &'a syn::Attribute>>(iter: I) -> Result<Self> { 149 let mut field_attrs = Self::default(); 150 151 for attr in iter { 152- if !attr.path.is_ident("merge") { 153+ if !attr.path().is_ident("merge") { 154 continue; 155 } 156 157 let parser = syn::punctuated::Punctuated::<FieldAttr, Token![,]>::parse_terminated; 158- for attr in attr.parse_args_with(parser).unwrap_or_abort() { 159+ for attr in attr.parse_args_with(parser)? { 160 field_attrs.apply(attr); 161 } 162 } 163 164- field_attrs 165+ Ok(field_attrs) 166+ } 167+ 168+ fn apply(&mut self, attr: FieldAttr) { 169+ match attr { 170+ FieldAttr::Skip => self.skip = true, 171+ FieldAttr::Strategy(path) => self.strategy = Some(path), 172+ } 173 } 174 } 175 176@@ -144,7 +147,10 @@ impl syn::parse::Parse for FieldAttr { 177 let path: syn::Path = input.parse()?; 178 Ok(FieldAttr::Strategy(path)) 179 } else { 180- abort!(name, "Unexpected attribute: {}", name) 181+ Err(Error::new_spanned( 182+ &name, 183+ format!("Unexpected attribute: {}", name), 184+ )) 185 } 186 } 187 } 188