-
Notifications
You must be signed in to change notification settings - Fork 68
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This fixes #28.
- Loading branch information
Showing
10 changed files
with
291 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
use quote::{Tokens, ToTokens}; | ||
use syn::{self, Ident}; | ||
|
||
use codegen::{ExtractAttribute, OuterFromImpl, TraitImpl}; | ||
use options::ForwardAttrs; | ||
|
||
pub struct FromTypeParamImpl<'a> { | ||
pub base: TraitImpl<'a>, | ||
pub ident: Option<&'a Ident>, | ||
pub attrs: Option<&'a Ident>, | ||
pub attr_names: Vec<&'a str>, | ||
pub forward_attrs: Option<&'a ForwardAttrs>, | ||
pub from_ident: bool, | ||
} | ||
|
||
impl<'a> ToTokens for FromTypeParamImpl<'a> { | ||
fn to_tokens(&self, tokens: &mut Tokens) { | ||
let input = self.param_name(); | ||
|
||
let error_declaration = self.base.declare_errors(); | ||
let grab_attrs = self.extractor(); | ||
let require_fields = self.base.require_fields(); | ||
let error_check = self.base.check_errors(); | ||
|
||
let default = if self.from_ident { | ||
quote!(let __default: Self = ::darling::export::From::from(#input.ident.clone());) | ||
} else { | ||
self.base.fallback_decl() | ||
}; | ||
|
||
let passed_ident = self.ident.as_ref().map(|i| quote!(#i: #input.ident.clone(),)); | ||
let passed_attrs = self.attrs.as_ref().map(|i| quote!(#i: __fwd_attrs,)); | ||
let initializers = self.base.initializers(); | ||
|
||
let map = self.base.map_fn(); | ||
|
||
self.wrap(quote! { | ||
fn from_type_param(#input: &::syn::TypeParam) -> ::darling::Result<Self> { | ||
#error_declaration | ||
|
||
#grab_attrs | ||
|
||
#require_fields | ||
|
||
#error_check | ||
|
||
#default | ||
|
||
::darling::export::Ok(Self { | ||
#passed_ident | ||
#passed_attrs | ||
#initializers | ||
}) #map | ||
} | ||
}, tokens); | ||
} | ||
} | ||
|
||
impl<'a> ExtractAttribute for FromTypeParamImpl<'a> { | ||
fn attr_names(&self) -> &[&str] { | ||
self.attr_names.as_slice() | ||
} | ||
|
||
fn forwarded_attrs(&self) -> Option<&ForwardAttrs> { | ||
self.forward_attrs | ||
} | ||
|
||
fn param_name(&self) -> Tokens { | ||
quote!(__type_param) | ||
} | ||
|
||
fn core_loop(&self) -> Tokens { | ||
self.base.core_loop() | ||
} | ||
|
||
fn local_declarations(&self) -> Tokens { | ||
self.base.local_declarations() | ||
} | ||
|
||
fn immutable_declarations(&self) -> Tokens { | ||
self.base.immutable_declarations() | ||
} | ||
} | ||
|
||
impl<'a> OuterFromImpl<'a> for FromTypeParamImpl<'a> { | ||
fn trait_path(&self) -> syn::Path { | ||
path!(::darling::FromTypeParam) | ||
} | ||
|
||
fn trait_bound(&self) -> syn::Path { | ||
path!(::darling::FromMetaItem) | ||
} | ||
|
||
fn base(&'a self) -> &'a TraitImpl<'a> { | ||
&self.base | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
use syn::{self, TypeParam}; | ||
|
||
use Result; | ||
|
||
/// Creates an instance by parsing an individual type_param and its attributes. | ||
pub trait FromTypeParam: Sized { | ||
fn from_type_param(type_param: &TypeParam) -> Result<Self>; | ||
} | ||
|
||
impl FromTypeParam for () { | ||
fn from_type_param(_: &TypeParam) -> Result<Self> { | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl FromTypeParam for TypeParam { | ||
fn from_type_param(type_param: &TypeParam) -> Result<Self> { | ||
Ok(type_param.clone()) | ||
} | ||
} | ||
|
||
impl FromTypeParam for Vec<syn::Attribute> { | ||
fn from_type_param(type_param: &TypeParam) -> Result<Self> { | ||
Ok(type_param.attrs.clone()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
use syn; | ||
|
||
use {Result}; | ||
use codegen::FromTypeParamImpl; | ||
use options::{ParseAttribute, ParseData, OuterFrom}; | ||
|
||
#[derive(Debug)] | ||
pub struct FromTypeParamOptions { | ||
pub base: OuterFrom, | ||
} | ||
|
||
impl FromTypeParamOptions { | ||
pub fn new(di: &syn::DeriveInput) -> Result<Self> { | ||
(FromTypeParamOptions { | ||
base: OuterFrom::start(di), | ||
}).parse_attributes(&di.attrs)?.parse_body(&di.data) | ||
} | ||
} | ||
|
||
impl ParseAttribute for FromTypeParamOptions { | ||
fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()> { | ||
self.base.parse_nested(mi) | ||
} | ||
} | ||
|
||
impl ParseData for FromTypeParamOptions { | ||
fn parse_variant(&mut self, variant: &syn::Variant) -> Result<()> { | ||
self.base.parse_variant(variant) | ||
} | ||
|
||
fn parse_field(&mut self, field: &syn::Field) -> Result<()> { | ||
self.base.parse_field(field) | ||
} | ||
} | ||
|
||
impl<'a> From<&'a FromTypeParamOptions> for FromTypeParamImpl<'a> { | ||
fn from(v: &'a FromTypeParamOptions) -> Self { | ||
FromTypeParamImpl { | ||
base: (&v.base.container).into(), | ||
ident: v.base.ident.as_ref(), | ||
attrs: v.base.attrs.as_ref(), | ||
attr_names: v.base.attr_names.as_strs(), | ||
forward_attrs: v.base.forward_attrs.as_ref(), | ||
from_ident: v.base.from_ident, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
#[macro_use] | ||
extern crate darling; | ||
extern crate syn; | ||
|
||
use darling::FromTypeParam; | ||
use syn::{DeriveInput, GenericParam, Ident, TypeParam}; | ||
|
||
#[darling(attributes(lorem), from_ident)] | ||
#[derive(FromTypeParam)] | ||
struct Lorem { | ||
ident: Ident, | ||
foo: bool, | ||
bar: Option<String>, | ||
} | ||
|
||
impl From<Ident> for Lorem { | ||
fn from(ident: Ident) -> Self { | ||
Lorem { | ||
ident, | ||
foo: false, | ||
bar: None, | ||
} | ||
} | ||
} | ||
|
||
fn extract_type(param: &GenericParam) -> &TypeParam { | ||
match *param { | ||
GenericParam::Type(ref ty) => ty, | ||
_ => unreachable!("Not a type param"), | ||
} | ||
} | ||
|
||
#[test] | ||
fn expand_many() { | ||
let di: DeriveInput = syn::parse_str(r#" | ||
struct Baz< | ||
#[lorem(foo)] T, | ||
#[lorem(bar = "x")] U: Eq + ?Sized | ||
>(T, U); | ||
"#).unwrap(); | ||
let params = di.generics.params; | ||
|
||
{ | ||
let ty = extract_type(¶ms[0]); | ||
let lorem = Lorem::from_type_param(ty).unwrap(); | ||
assert_eq!(lorem.ident.as_ref(), "T"); | ||
assert_eq!(lorem.foo, true); | ||
assert_eq!(lorem.bar, None); | ||
} | ||
|
||
{ | ||
let ty = extract_type(¶ms[1]); | ||
let lorem = Lorem::from_type_param(ty).unwrap(); | ||
assert_eq!(lorem.ident.as_ref(), "U"); | ||
assert_eq!(lorem.foo, false); | ||
assert_eq!(lorem.bar, Some("x".to_string())); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
#[macro_use] | ||
extern crate darling; | ||
extern crate syn; | ||
|
||
use darling::FromTypeParam; | ||
use syn::{DeriveInput, GenericParam, TypeParam}; | ||
|
||
#[darling(attributes(lorem), default)] | ||
#[derive(Default, FromTypeParam)] | ||
struct Lorem { | ||
foo: bool, | ||
bar: Option<String>, | ||
} | ||
|
||
fn extract_type(param: &GenericParam) -> &TypeParam { | ||
match *param { | ||
GenericParam::Type(ref ty) => ty, | ||
_ => unreachable!("Not a type param"), | ||
} | ||
} | ||
|
||
#[test] | ||
fn expand_many() { | ||
let di: DeriveInput = syn::parse_str(r#" | ||
struct Baz< | ||
#[lorem(foo)] T, | ||
#[lorem(bar = "x")] U: Eq + ?Sized | ||
>(T, U); | ||
"#).unwrap(); | ||
let params = di.generics.params; | ||
|
||
{ | ||
let ty = extract_type(¶ms[0]); | ||
let lorem = Lorem::from_type_param(ty).unwrap(); | ||
assert_eq!(lorem.foo, true); | ||
assert_eq!(lorem.bar, None); | ||
} | ||
|
||
{ | ||
let ty = extract_type(¶ms[1]); | ||
let lorem = Lorem::from_type_param(ty).unwrap(); | ||
assert_eq!(lorem.foo, false); | ||
assert_eq!(lorem.bar, Some("x".to_string())); | ||
} | ||
} |