gtk_rust_app_derive/widget/
store.rs1use quote::{__private::TokenStream, quote};
4use syn::{
5 parenthesized,
6 parse::Parse,
7 parse2,
8 punctuated::Punctuated,
9 token::{Comma, Dot, Paren},
10 Attribute, Field, Ident,
11};
12
13use super::attributes::ATTR_SELECTOR;
14
15struct Args {
16 pub _parent_token: Paren,
17 pub paths: Vec<Punctuated<Ident, Dot>>,
18}
19
20impl Parse for Args {
21 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
22 let content;
23 let parent_token = parenthesized!(content in input);
24 let mut selectors = Vec::new();
25 let selector = Punctuated::new();
26 selectors.push(selector);
27 while !content.is_empty() {
28 if content.lookahead1().peek(Comma) {
29 let _comma: Comma = content.parse().unwrap();
30 selectors.push(Punctuated::new());
31 continue;
32 }
33 if content.lookahead1().peek(Dot) {
34 let _dor: Dot = content.parse().unwrap();
35 continue;
36 }
37 let ident: Ident = content.parse().unwrap();
38 if let Some(s) = selectors.last_mut() {
39 s.push(ident);
40 }
41 }
42 Ok(Self {
43 _parent_token: parent_token,
44 paths: selectors,
45 })
46 }
47}
48
49pub fn get_selector_bindings(fields: &Punctuated<Field, Comma>) -> TokenStream {
50 let mut tokens = TokenStream::new();
51 for field in fields {
52 if let Some(attr) = get_selector_attr(field) {
53 let name = field.ident.as_ref().unwrap();
54 let attr_tokens = &attr.tokens;
55 let args: Args = parse2(attr_tokens.clone()).unwrap();
56 let paths = args.paths;
57 let sd = quote!(
58 {
59 let obj = self.obj();
60 #[allow(clippy::redundant_closure_call)]
61 let selector_id = store().select(
62 stringify!(#name),
63 |s| {
64 let mut state: State = Default::default();
65 #(
66 let sel = |state: &State| #paths.clone();
67 #paths = sel(s);
68 )*
69 state
70 },
71 glib::clone!(@weak obj => move |state| {
72 <Self as ObjectSubclass>::Type::#name(&obj, state);
73 })
74 );
75 let mut selectors = self.selectors.take();
76 selectors.push(selector_id);
77 self.selectors.set(selectors);
78 }
79 );
80 tokens.extend(sd)
82 }
83 }
84 tokens
85}
86
87fn get_selector_attr(field: &Field) -> Option<&Attribute> {
88 for attr in &field.attrs {
89 if attr.path.is_ident(ATTR_SELECTOR) {
90 return Some(attr);
91 }
92 }
93 None
94}