freya_elements/
macros.rs

1#[macro_export]
2macro_rules! def_element {
3    (
4        $(
5            $(#[$attr:meta])*
6            $name:ident {
7                $(
8                    $(#[$attr_method:meta])*
9                    $fil:ident,
10                )*
11            };
12         )*
13        ) => {
14        $(
15            $crate::impl_element!(
16                $(#[$attr])*
17                $name {
18                    $(
19                        $(#[$attr_method])*
20                        $fil,
21                    )*
22                };
23            );
24        )*
25
26        /// This module contains helpers for rust analyzer autocompletion
27        #[doc(hidden)]
28        pub mod completions {
29            /// This helper tells rust analyzer that it should autocomplete the element name with braces.
30            #[allow(non_camel_case_types)]
31            pub enum CompleteWithBraces {
32                $(
33                    $(#[$attr])*
34                    $name {}
35                ),*
36            }
37        }
38    };
39}
40
41#[macro_export]
42macro_rules! impl_element {
43    (
44        $(
45            $(#[$attr:meta])*
46            $name:ident {
47                $(
48                    $(#[$attr_method:meta])*
49                    $fil:ident,
50                )*
51            };
52         )*
53    ) => {
54        $(
55            #[allow(non_camel_case_types)]
56            $(#[$attr])*
57            pub mod $name {
58                #[doc(hidden)]
59                pub const TAG_NAME: &'static str = stringify!($name);
60                #[doc(hidden)]
61                pub const NAME_SPACE: Option<&'static str> = None;
62
63                $(
64                   pub use $crate::attributes::$fil::$fil;
65                )*
66            }
67        )*
68    };
69}
70
71#[macro_export]
72macro_rules! def_attribute {
73    (
74        $(
75            $(#[$attr:meta])*
76            $fil:ident,
77         )*
78    ) => {
79        $(
80            #[allow(non_camel_case_types)]
81            pub mod $fil {
82
83                #[allow(non_upper_case_globals)]
84                $(#[$attr])*
85                pub const $fil: (&'static str, Option<&'static str>, bool) = (stringify!($fil), None, false);
86            }
87        )*
88    };
89}
90
91#[macro_export]
92macro_rules! impl_event {
93        (
94            $data:ty;
95            $(
96                $( #[$attr:meta] )*
97                $name:ident $(: $event:literal)?
98            )*
99        ) => {
100            $(
101                $( #[$attr] )*
102                #[inline]
103                pub fn $name<__Marker>(mut _f: impl ::dioxus_core::prelude::SuperInto<::dioxus_core::prelude::EventHandler<::dioxus_core::Event<$data>>, __Marker>) -> ::dioxus_core::Attribute {
104                    // super into will make a closure that is owned by the current owner (either the child component or the parent component).
105                    // We can't change that behavior in a minor version because it would cause issues with Components that accept event handlers.
106                    // Instead we run super into with an owner that is moved into the listener closure so it will be dropped when the closure is dropped.
107                    let owner = <::generational_box::UnsyncStorage as ::generational_box::AnyStorage>::owner();
108                    let event_handler = ::dioxus_core::prelude::with_owner(owner.clone(), || _f.super_into());
109                    ::dioxus_core::Attribute::new(
110                        impl_event!(@name $name $($event)?),
111                        ::dioxus_core::AttributeValue::listener(move |e: ::dioxus_core::Event<$crate::events::ErasedEventData>| {
112                            // Force the owner to be moved into the event handler
113                            _ = &owner;
114                            event_handler.call(e.map(|e| e.into()));
115                        }),
116                        None,
117                        false,
118                    ).into()
119                }
120
121                #[doc(hidden)]
122                $( #[$attr] )*
123                pub mod $name {
124                    use super::*;
125
126                    // When expanding the macro, we use this version of the function if we see an inline closure to give better type inference
127                    $( #[$attr] )*
128                    pub fn call_with_explicit_closure<
129                        __Marker,
130                        Return: ::dioxus_core::SpawnIfAsync<__Marker> + 'static,
131                    >(
132                        event_handler: impl FnMut(::dioxus_core::Event<$data>) -> Return + 'static,
133                    ) -> ::dioxus_core::Attribute {
134                        #[allow(deprecated)]
135                        super::$name(event_handler)
136                    }
137                }
138            )*
139        };
140
141        (@name $name:ident) => {
142            stringify!($name)
143        };
144    }
145
146#[doc(hidden)]
147#[allow(dead_code)]
148pub trait EventReturn<P>: Sized {
149    fn spawn(self) {}
150}
151
152impl EventReturn<()> for () {}
153#[doc(hidden)]
154pub struct AsyncMarker;
155
156impl<T> EventReturn<AsyncMarker> for T
157where
158    T: std::future::Future<Output = ()> + 'static,
159{
160    #[inline]
161    fn spawn(self) {
162        dioxus_core::prelude::spawn(self);
163    }
164}