Skip to content

Commit

Permalink
Implement Associated Types. (#6)
Browse files Browse the repository at this point in the history
* Implement Associated Types.
* Copy over attributes on associated types.
* cargo fmt
  • Loading branch information
najamelan authored Jun 5, 2021
1 parent 158c7d4 commit 3b493f0
Show file tree
Hide file tree
Showing 10 changed files with 643 additions and 21 deletions.
105 changes: 100 additions & 5 deletions src/derive/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@ use crate::utils::signature_to_method_call;
use crate::utils::trait_to_generic_ident;

pub fn derive(trait_: &syn::ItemTrait) -> syn::Result<syn::ItemImpl> {
// build the methods
// build an identifier for the generic type used for the implementation
let trait_ident = &trait_.ident;
let generic_type = trait_to_generic_ident(&trait_);

// build the methods & associated types.
let mut methods: Vec<syn::ImplItemMethod> = Vec::new();
let mut assoc_types: Vec<syn::ImplItemType> = Vec::new();
for item in trait_.items.iter() {
if let syn::TraitItem::Method(ref m) = item {
if let Some(receiver) = m.sig.receiver() {
Expand Down Expand Up @@ -36,11 +41,14 @@ pub fn derive(trait_: &syn::ItemTrait) -> syn::Result<syn::ItemImpl> {
let item = parse_quote!(#[inline] #signature { #call });
methods.push(item)
}
}

// build an identifier for the generic type used for the implementation
let trait_ident = &trait_.ident;
let generic_type = trait_to_generic_ident(&trait_);
if let syn::TraitItem::Type(t) = item {
let t_ident = &t.ident;
let attrs = &t.attrs;
let item = parse_quote!( #(#attrs)* type #t_ident = <#generic_type as #trait_ident>::#t_ident ; );
assoc_types.push(item);
}
}

// build the generics for the impl block:
// we use the same generics as the trait itself, plus
Expand All @@ -61,6 +69,7 @@ pub fn derive(trait_: &syn::ItemTrait) -> syn::Result<syn::ItemImpl> {
Ok(parse_quote!(
#[automatically_derived]
impl #impl_generics #trait_ident #trait_generic_names for std::sync::Arc<#generic_type> #where_clause {
#(#assoc_types)*
#(#methods)*
}
))
Expand Down Expand Up @@ -187,5 +196,91 @@ mod tests {
)
);
}

#[test]
fn associated_types() {
let trait_ = parse_quote!(
trait MyTrait {
type Return;
}
);
let derived = super::super::derive(&trait_).unwrap();

assert_eq!(
derived,
parse_quote!(
#[automatically_derived]
impl<MT: MyTrait + ?Sized> MyTrait for std::sync::Arc<MT> {
type Return = <MT as MyTrait>::Return;
}
)
);
}

#[test]
fn associated_types_bound() {
let trait_ = parse_quote!(
trait MyTrait {
type Return: Clone;
}
);
let derived = super::super::derive(&trait_).unwrap();

assert_eq!(
derived,
parse_quote!(
#[automatically_derived]
impl<MT: MyTrait + ?Sized> MyTrait for std::sync::Arc<MT> {
type Return = <MT as MyTrait>::Return;
}
)
);
}

#[test]
fn associated_types_dodgy_name() {
let trait_ = parse_quote!(
trait MyTrait {
type r#type;
}
);
let derived = super::super::derive(&trait_).unwrap();

assert_eq!(
derived,
parse_quote!(
#[automatically_derived]
impl<MT: MyTrait + ?Sized> MyTrait for std::sync::Arc<MT> {
type r#type = <MT as MyTrait>::r#type;
}
)
);
}

#[test]
fn associated_types_attrs() {
let trait_ = parse_quote!(
trait MyTrait {
#[cfg(target_arch = "wasm32")]
type Return;
#[cfg(not(target_arch = "wasm32"))]
type Return: Send;
}
);
let derived = super::super::derive(&trait_).unwrap();

assert_eq!(
derived,
parse_quote!(
#[automatically_derived]
impl<MT: MyTrait + ?Sized> MyTrait for std::sync::Arc<MT> {
#[cfg(target_arch = "wasm32")]
type Return = <MT as MyTrait>::Return;
#[cfg(not(target_arch = "wasm32"))]
type Return = <MT as MyTrait>::Return;
}
)
);
}
}
}
103 changes: 99 additions & 4 deletions src/derive/box.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@ use crate::utils::{
};

pub fn derive(trait_: &syn::ItemTrait) -> syn::Result<syn::ItemImpl> {
// build an identifier for the generic type used for the implementation
let trait_ident = &trait_.ident;
let generic_type = trait_to_generic_ident(&trait_);

// build the methods
let mut methods: Vec<syn::ImplItemMethod> = Vec::new();
let mut assoc_types: Vec<syn::ImplItemType> = Vec::new();
for item in trait_.items.iter() {
if let syn::TraitItem::Method(ref m) = item {
let signature = &m.sig;
Expand All @@ -33,11 +38,14 @@ pub fn derive(trait_: &syn::ItemTrait) -> syn::Result<syn::ItemImpl> {
let item = parse_quote!(#[inline] #signature { #call });
methods.push(item)
}
}

// build an identifier for the generic type used for the implementation
let trait_ident = &trait_.ident;
let generic_type = trait_to_generic_ident(&trait_);
if let syn::TraitItem::Type(t) = item {
let t_ident = &t.ident;
let attrs = &t.attrs;
let item = parse_quote!( #(#attrs)* type #t_ident = <#generic_type as #trait_ident>::#t_ident ; );
assoc_types.push(item);
}
}

// build the generics for the impl block:
// we use the same generics as the trait itself, plus
Expand All @@ -59,6 +67,7 @@ pub fn derive(trait_: &syn::ItemTrait) -> syn::Result<syn::ItemImpl> {
Ok(parse_quote!(
#[automatically_derived]
impl #impl_generics #trait_ident #trait_generic_names for Box<#generic_type> #where_clause {
#(#assoc_types)*
#(#methods)*
}
))
Expand Down Expand Up @@ -205,5 +214,91 @@ mod tests {
)
);
}

#[test]
fn associated_types() {
let trait_ = parse_quote!(
trait MyTrait {
type Return;
}
);
let derived = super::super::derive(&trait_).unwrap();

assert_eq!(
derived,
parse_quote!(
#[automatically_derived]
impl<MT: MyTrait> MyTrait for Box<MT> {
type Return = <MT as MyTrait>::Return;
}
)
);
}

#[test]
fn associated_types_bound() {
let trait_ = parse_quote!(
trait MyTrait {
type Return: Clone;
}
);
let derived = super::super::derive(&trait_).unwrap();

assert_eq!(
derived,
parse_quote!(
#[automatically_derived]
impl<MT: MyTrait> MyTrait for Box<MT> {
type Return = <MT as MyTrait>::Return;
}
)
);
}

#[test]
fn associated_types_dodgy_name() {
let trait_ = parse_quote!(
trait MyTrait {
type r#type;
}
);
let derived = super::super::derive(&trait_).unwrap();

assert_eq!(
derived,
parse_quote!(
#[automatically_derived]
impl<MT: MyTrait> MyTrait for Box<MT> {
type r#type = <MT as MyTrait>::r#type;
}
)
);
}

#[test]
fn associated_types_attrs() {
let trait_ = parse_quote!(
trait MyTrait {
#[cfg(target_arch = "wasm32")]
type Return;
#[cfg(not(target_arch = "wasm32"))]
type Return: Send;
}
);
let derived = super::super::derive(&trait_).unwrap();

assert_eq!(
derived,
parse_quote!(
#[automatically_derived]
impl<MT: MyTrait> MyTrait for Box<MT> {
#[cfg(target_arch = "wasm32")]
type Return = <MT as MyTrait>::Return;
#[cfg(not(target_arch = "wasm32"))]
type Return = <MT as MyTrait>::Return;
}
)
);
}
}
}
103 changes: 99 additions & 4 deletions src/derive/mut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@ use crate::utils::{
};

pub fn derive(trait_: &syn::ItemTrait) -> syn::Result<syn::ItemImpl> {
// build an identifier for the generic type used for the implementation
let trait_ident = &trait_.ident;
let generic_type = trait_to_generic_ident(&trait_);

// build the methods
let mut methods: Vec<syn::ImplItemMethod> = Vec::new();
let mut assoc_types: Vec<syn::ImplItemType> = Vec::new();
for item in trait_.items.iter() {
if let syn::TraitItem::Method(ref m) = item {
if let Some(receiver) = m.sig.receiver() {
Expand All @@ -30,11 +35,14 @@ pub fn derive(trait_: &syn::ItemTrait) -> syn::Result<syn::ItemImpl> {
let item = parse_quote!(#[inline] #signature { #call });
methods.push(item)
}
}

// build an identifier for the generic type used for the implementation
let trait_ident = &trait_.ident;
let generic_type = trait_to_generic_ident(&trait_);
if let syn::TraitItem::Type(t) = item {
let t_ident = &t.ident;
let attrs = &t.attrs;
let item = parse_quote!( #(#attrs)* type #t_ident = <#generic_type as #trait_ident>::#t_ident ; );
assoc_types.push(item);
}
}

// build the generics for the impl block:
// we use the same generics as the trait itself, plus
Expand All @@ -55,6 +63,7 @@ pub fn derive(trait_: &syn::ItemTrait) -> syn::Result<syn::ItemImpl> {
Ok(parse_quote!(
#[automatically_derived]
impl #impl_generics #trait_ident #trait_generic_names for &mut #generic_type #where_clause {
#(#assoc_types)*
#(#methods)*
}
))
Expand Down Expand Up @@ -172,5 +181,91 @@ mod tests {
)
);
}

#[test]
fn associated_types() {
let trait_ = parse_quote!(
trait MyTrait {
type Return;
}
);
let derived = super::super::derive(&trait_).unwrap();

assert_eq!(
derived,
parse_quote!(
#[automatically_derived]
impl<MT: MyTrait + ?Sized> MyTrait for &mut MT {
type Return = <MT as MyTrait>::Return;
}
)
);
}

#[test]
fn associated_types_bound() {
let trait_ = parse_quote!(
trait MyTrait {
type Return: Clone;
}
);
let derived = super::super::derive(&trait_).unwrap();

assert_eq!(
derived,
parse_quote!(
#[automatically_derived]
impl<MT: MyTrait + ?Sized> MyTrait for &mut MT {
type Return = <MT as MyTrait>::Return;
}
)
);
}

#[test]
fn associated_types_dodgy_name() {
let trait_ = parse_quote!(
trait MyTrait {
type r#type;
}
);
let derived = super::super::derive(&trait_).unwrap();

assert_eq!(
derived,
parse_quote!(
#[automatically_derived]
impl<MT: MyTrait + ?Sized> MyTrait for &mut MT {
type r#type = <MT as MyTrait>::r#type;
}
)
);
}

#[test]
fn associated_types_attrs() {
let trait_ = parse_quote!(
trait MyTrait {
#[cfg(target_arch = "wasm32")]
type Return;
#[cfg(not(target_arch = "wasm32"))]
type Return: Send;
}
);
let derived = super::super::derive(&trait_).unwrap();

assert_eq!(
derived,
parse_quote!(
#[automatically_derived]
impl<MT: MyTrait + ?Sized> MyTrait for &mut MT {
#[cfg(target_arch = "wasm32")]
type Return = <MT as MyTrait>::Return;
#[cfg(not(target_arch = "wasm32"))]
type Return = <MT as MyTrait>::Return;
}
)
);
}
}
}
Loading

0 comments on commit 3b493f0

Please sign in to comment.