qtbridge_gen/qt_derive/
qmodelitem.rs1use proc_macro::TokenStream;
2use quote::{quote, format_ident};
3use syn::DeriveInput;
4use std::collections::HashMap;
5
6pub fn try_derive_qmodelitem(input: TokenStream) -> syn::Result<TokenStream> {
7 let input: DeriveInput = syn::parse(input)?;
8 let name = &input.ident;
9
10 let s = match &input.data {
11 syn::Data::Struct(st) => st,
12 _ => return Err(syn::Error::new_spanned(&input, "QModelItem only supports structs")),
13 };
14
15 let fields = s.fields.iter().collect::<Vec<_>>();
16
17 let (members, field_names): (Vec<_>, Vec<_>) = fields.iter().enumerate()
18 .map(|(i, f)|
19 match f.ident.as_ref() {
20 Some(ident) => (quote! { self.#ident }, ident.to_string()),
21 None => {
22 let index = syn::Index::from(i);
23 (quote! { self.#index }, format!("_{}", i))
24 },
25 })
26 .unzip();
27
28 let len = fields.len();
29 let max_elements = 15;
30
31 if len > max_elements {
32 return Err(syn::Error::new_spanned(&s.fields, "QModelItem supports only up to 15 fields"));
33 }
34
35 let field_types = fields.iter().map(|f| &f.ty).collect::<Vec<_>>();
36
37 let default_roles: HashMap<&str, i32> = HashMap::from([
39 ("display", 0x0),
40 ("decoration", 0x1),
41 ("edit", 0x2),
42 ("toolTip", 0x3),
43 ("statusTip", 0x4),
44 ("whatsThis", 0x5),
45 ]);
46
47 let mut prop_mapping = Vec::new();
48
49 prop_mapping.resize(field_names.len(), max_elements);
53 for (i, f) in field_names.iter().enumerate() {
54 if let Some(&predef) = default_roles.get(f.as_str()) {
55 prop_mapping[predef as usize] = i;
56 }
57 }
58 let mut j = 0;
59 for (i, f) in field_names.iter().enumerate() {
60 if !default_roles.contains_key(f.as_str()){
61 while prop_mapping[j] < max_elements {
62 j += 1;
63 }
64 prop_mapping[j] = i;
65 j += 1;
66 }
67 }
68
69 let mut typdefs = Vec::new();
70 let mut getters = Vec::new();
71 let mut setters = Vec::new();
72
73 for (i, member) in members.iter().enumerate() {
74 let getter_fn_ident = format_ident!("get{}", prop_mapping[i]);
75 let setter_fn_ident = format_ident!("set{}", prop_mapping[i]);
76 let type_ident = format_ident!("T{}", prop_mapping[i]);
77 let ty = &field_types[i];
78
79 typdefs.push(quote! { type #type_ident = #ty; });
80 getters.push(quote! { fn #getter_fn_ident(&self) -> Option<&#ty> { Some(&#member) } });
81 setters.push(quote! { fn #setter_fn_ident(&mut self, value: #ty) { #member = value; } });
82 }
83
84 for i in len..15 {
85 let type_ident = format_ident!("T{}", i);
86 typdefs.push(quote! { type #type_ident = (); });
87 }
88
89 let mut role_tokens = Vec::new();
90
91 for (i,f) in field_names.iter().enumerate() {
92 let idx = prop_mapping[i] as i32;
93
94 role_tokens.push(quote! {
95 (#idx, #f.into()),
96 });
97 }
98
99 Ok(quote! {
100 impl QModelItem for #name {
101
102 #(#typdefs)*
103
104 #(#getters)*
105
106 #(#setters)*
107
108 fn role_names() -> HashMap<i32, String> {
109 let roles = [
110 #(#role_tokens)*
111 ];
112 roles.iter().cloned().collect()
113 }
114 }
115 }.into())
116}