1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
use proc_macro::TokenStream;

use crate::gxi_parser::*;
use crate::init_type::*;
use crate::tree_parser::*;

mod gxi_parser;
mod init_type;
mod tree_parser;

/// proc-macro for writing gxi components
///
/// ## Syntax
///
/// ```rust
/// gxi! {
///     NameOfComponent { // Constructor block
///          count : u32 = 0 // property : type = default value ; (optional)
///     }
///     update { // gxi_update_macro function (Optional)
///         // The business logic goes here
///     }
///     render { // render function (Optional)
///          { /* Component tree goes here */ }
///          Component
///     }
/// };
/// ```
/// ## Render Block
/// The component tree is written in this block. It produces the render function as follows.
///
/// ```rust
///# use std::rc::Rc;
/// fn render(this: NodeRc) {
///    let cont = Rc::clone(&this);
///    let node = cont.clone();
///    let state = {
///        let mut node_borrow = this.as_ref().borrow_mut();
///        let node = node_borrow.as_any_mut().downcast_mut::<Self>().unwrap();
///        if !node.is_dirty() {
///            return;
///        }
///        node.mark_clean();
///        node.state.clone()
///    };
///    let state = state.lock().unwrap();
///    // the content of the render block is moved here
/// }
/// ```
///
/// It is recommended not to write the render function manually. Use the render block instead.
/// Synctax for the render block can be found [here](../gxi_c_macro/macro.gxi_c_macro.html#Syntax)
/// ## Update Block
/// *The gxi_update_macro block produces*
///
/// ```rust
/// #[update(NameOfComponent)]
/// async fn update<F: Fn() + 'static>(state: State, msg: Msg, render: F) -> AsyncResult<ShouldRender> {
///     // the content of the gxi_update_macro block is moved here
/// }
/// ```
///
/// In this block values `state: State, msg: Msg, render: F` are present which can be used as follows ->
///
/// * `state` - is of `type State = Arc<Mutex<ComponentState>>;` where `ComponentState` has all the fields defined in the
///     constructor block. It must be used to manipulate the state of the component. For efficient renders, the dev should drop the lock
///     on the mutex before awaiting an async call.
///
/// * `msg` - This is the enum defined by the user outside the macro.
///     `Example`
///     ```rust
///     enum Msg {
///         Task
///     }
///     ```
///
/// * `render`- is a closure that can be called to pre-render the component. This can be used in situations where
///     the final value of an async function is not yet received but the user has to be notified about the progress.
///     A popular example is progress bars.
///
#[proc_macro]
pub fn gxi(item: TokenStream) -> TokenStream {
    let GxiParser { tree } = syn::parse_macro_input!(item as GxiParser);
    tree.into()
}