forked from JelteF/derive_more
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support pointwise addition for arrays and tuples
Fixes JelteF#342 We want to support examples like these: ```rust struct StructRecursive { a: i32, b: [i32; 2], c: [[i32; 2]; 3], d: (i32, i32), e: ((u8, [i32; 3]), i32), f: ((u8, i32), (u8, ((i32, u64, ((u8, u8), u16)), u8))), g: i32, } struct TupleRecursive((i32, u8), [(i32, u8); 10]); ``` Supporting arrays and tuples inside of enums would also be useful, but that's not in this PR.
- Loading branch information
1 parent
2a001d6
commit 2777c6e
Showing
3 changed files
with
86 additions
and
20 deletions.
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 |
---|---|---|
@@ -1,28 +1,68 @@ | ||
use proc_macro2::TokenStream; | ||
use proc_macro2::{Span, TokenStream}; | ||
use quote::quote; | ||
use syn::{Field, Ident, Index}; | ||
use syn::{Field, Ident, Index, Type, TypeArray, TypeTuple}; | ||
|
||
pub fn tuple_exprs(fields: &[&Field], method_ident: &Ident) -> Vec<TokenStream> { | ||
let mut exprs = vec![]; | ||
|
||
for i in 0..fields.len() { | ||
let i = Index::from(i); | ||
// generates `self.0.add(rhs.0)` | ||
let expr = quote! { self.#i.#method_ident(rhs.#i) }; | ||
exprs.push(expr); | ||
} | ||
exprs | ||
let fields: Vec<&Type> = fields.iter().map(|field| &field.ty).collect::<Vec<_>>(); | ||
inner_tuple_exprs(0, "e! {}, &fields, method_ident) | ||
} | ||
|
||
pub fn struct_exprs(fields: &[&Field], method_ident: &Ident) -> Vec<TokenStream> { | ||
let mut exprs = vec![]; | ||
fields | ||
.iter() | ||
.map(|field| { | ||
// It's safe to unwrap because struct fields always have an identifier | ||
let field_path = field.ident.as_ref().unwrap(); | ||
elem_content(0, "e! { .#field_path }, &field.ty, method_ident) | ||
}) | ||
.collect() | ||
} | ||
|
||
pub fn inner_tuple_exprs( | ||
// `depth` is needed for `index_var` generation for nested arrays | ||
depth: usize, | ||
field_path: &TokenStream, | ||
fields: &[&Type], | ||
method_ident: &Ident, | ||
) -> Vec<TokenStream> { | ||
fields | ||
.iter() | ||
.enumerate() | ||
.map(|(i, ty)| { | ||
let i = Index::from(i); | ||
elem_content(depth + 1, "e! { #field_path.#i }, ty, method_ident) | ||
}) | ||
.collect() | ||
} | ||
|
||
pub fn elem_content( | ||
depth: usize, | ||
field_path: &TokenStream, | ||
ty: &Type, | ||
method_ident: &Ident, | ||
) -> TokenStream { | ||
match ty { | ||
Type::Array(TypeArray { elem, .. }) => { | ||
let index_var = Ident::new(&format!("i{}", depth), Span::call_site()); | ||
let fn_body = elem_content( | ||
depth + 1, | ||
"e! { #field_path[#index_var] }, | ||
elem.as_ref(), | ||
method_ident, | ||
); | ||
|
||
for field in fields { | ||
// It's safe to unwrap because struct fields always have an identifier | ||
let field_id = field.ident.as_ref().unwrap(); | ||
// generates `x: self.x.add(rhs.x)` | ||
let expr = quote! { self.#field_id.#method_ident(rhs.#field_id) }; | ||
exprs.push(expr) | ||
quote! { core::array::from_fn(|#index_var| #fn_body) } | ||
} | ||
Type::Tuple(TypeTuple { elems, .. }) => { | ||
let exprs = inner_tuple_exprs( | ||
depth + 1, | ||
field_path, | ||
&elems.iter().collect::<Vec<_>>(), | ||
method_ident, | ||
); | ||
quote! { (#(#exprs),*) } | ||
} | ||
// generates `self.x.add(rhs.x)` | ||
_ => quote! { self #field_path.#method_ident(rhs #field_path) }, | ||
} | ||
exprs | ||
} |
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