gtk_rust_app_derive/widget/
store.rs

1// SPDX-License-Identifier: GPL-3.0-or-later
2
3use 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            // println!("{}", sd);
81            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}