Skip to content

Commit 183853b

Browse files
authored
fix: added logic for struct inside macro_rules! (#41)
Fixes #40
1 parent d112aa2 commit 183853b

File tree

2 files changed

+38
-22
lines changed

2 files changed

+38
-22
lines changed

xcp_type_description/xcp_type_description_derive/src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ extern crate proc_macro;
33
mod utils;
44

55
use proc_macro::TokenStream;
6+
use quote::ToTokens;
67
use quote::quote;
78
use syn::{Data, DeriveInput, Expr, parse_macro_input};
89

@@ -26,9 +27,9 @@ pub fn xcp_type_description_derive(input: TokenStream) -> TokenStream {
2627
fn generate_type_description_impl(data_struct: syn::DataStruct, value_type: &syn::Ident) -> proc_macro2::TokenStream {
2728
let field_handlers = data_struct.fields.iter().map(|field| {
2829
let field_name = &field.ident; // Field identifier
29-
let field_data_type = &field.ty; // Field type
30+
let raw_type_tokens = field.ty.to_token_stream();
31+
let field_data_type = &syn::parse2(utils::normalize_tokens(raw_type_tokens)).expect("failed to parse normalized"); // Field type
3032
let (x_dim, y_dim) = dimensions(field_data_type); //Dimension of type is array
31-
3233
// Field attributes
3334
// #[axis/characteristic/measurement(...)] attr = access_type, comment, min, max, step, factor, offset, unit, x_axis, y_axis
3435
let field_attributes = &field.attrs;

xcp_type_description/xcp_type_description_derive/src/utils.rs

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -99,32 +99,47 @@ pub fn parse_field_attributes(
9999
(field_attribute, qualifier, comment, min, max, step, factor.unwrap(), offset.unwrap(), unit, x_axis, y_axis)
100100
}
101101

102-
pub fn dimensions(ty: &Type) -> (u16, u16) {
102+
pub fn normalize_tokens(ts: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
103+
ts.into_iter()
104+
.flat_map(|tt| match tt {
105+
proc_macro2::TokenTree::Group(g) if g.delimiter() == proc_macro2::Delimiter::None => normalize_tokens(g.stream()).into_iter().collect::<Vec<_>>(),
106+
other => vec![other],
107+
})
108+
.collect()
109+
}
110+
111+
pub fn dimensions(ty: &syn::Type) -> (u16, u16) {
103112
match ty {
104-
Type::Array(TypeArray { elem, len, .. }) => {
105-
let length = match len {
106-
syn::Expr::Lit(expr_lit) => {
107-
if let Lit::Int(lit_int) = &expr_lit.lit {
108-
lit_int.base10_parse::<usize>().unwrap()
109-
} else {
110-
panic!("Expected an integer literal for array length");
111-
}
112-
}
113-
_ => panic!("Expected an integer literal for array length"),
114-
};
113+
syn::Type::Array(arr) => handle_array(arr),
114+
115+
_ => (0, 0),
116+
}
117+
}
115118

116-
let (inner_x, inner_y) = dimensions(elem);
119+
fn handle_array(arr: &syn::TypeArray) -> (u16, u16) {
120+
let len = extract_array_len(&arr.len).unwrap_or(0);
121+
let (ix, iy) = dimensions(&arr.elem);
122+
if ix == 0 && iy == 0 {
123+
(len as u16, 0)
124+
} else if iy == 0 {
125+
(ix, len as u16)
126+
} else {
127+
(ix, iy * len as u16)
128+
}
129+
}
117130

118-
if inner_x == 0 && inner_y == 0 {
119-
(length.try_into().unwrap(), 0)
120-
} else if inner_y == 0 {
121-
(inner_x, length.try_into().unwrap())
131+
fn extract_array_len(expr: &syn::Expr) -> Option<usize> {
132+
match expr {
133+
syn::Expr::Lit(l) => {
134+
if let syn::Lit::Int(i) = &l.lit {
135+
i.base10_parse().ok()
122136
} else {
123-
// @@@@ TODO ????
124-
(inner_x, inner_y)
137+
panic!("Expected an integer literal for array length");
125138
}
126139
}
127-
_ => (0, 0),
140+
syn::Expr::Paren(p) => extract_array_len(&p.expr),
141+
syn::Expr::Group(g) => extract_array_len(&g.expr),
142+
_ => panic!("Expected an integer literal for array length"),
128143
}
129144
}
130145

0 commit comments

Comments
 (0)