waterui_core/
macros.rs

1/// Implements a basic `Debug` trait for types using their type name.
2///
3/// This macro generates a `Debug` implementation that simply prints the type name,
4/// useful for types where the internal structure doesn't need to be exposed.
5#[macro_export]
6macro_rules! impl_debug {
7    ($ty:ty) => {
8        impl core::fmt::Debug for $ty {
9            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
10                f.write_str(core::any::type_name::<Self>())
11            }
12        }
13    };
14}
15
16/// Implements a native view that is handled by the platform backend.
17///
18/// This macro implements both `NativeView` and `View` traits for a type.
19/// The `View::body()` returns `Native(self)` to delegate to the native backend.
20///
21/// # Usage
22///
23/// ```ignore
24/// // Default stretch axis (None)
25/// raw_view!(Text);
26///
27/// // With explicit stretch axis
28/// raw_view!(Color, StretchAxis::Both);
29/// raw_view!(Spacer, StretchAxis::MainAxis);
30/// ```
31#[macro_export]
32macro_rules! raw_view {
33    // With explicit stretch axis
34    ($ty:ty, $axis:expr) => {
35        impl $crate::NativeView for $ty {
36            fn stretch_axis(&self) -> $crate::layout::StretchAxis {
37                $axis
38            }
39        }
40
41        impl $crate::View for $ty {
42            fn body(self, _env: &$crate::Environment) -> impl $crate::View {
43                $crate::Native::new(self)
44            }
45
46            fn stretch_axis(&self) -> $crate::layout::StretchAxis {
47                $axis
48            }
49        }
50    };
51
52    // Default stretch axis (None)
53    ($ty:ty) => {
54        impl $crate::NativeView for $ty {}
55
56        impl $crate::View for $ty {
57            fn body(self, _env: &$crate::Environment) -> impl $crate::View {
58                $crate::Native::new(self)
59            }
60
61            fn stretch_axis(&self) -> $crate::layout::StretchAxis {
62                $crate::layout::StretchAxis::None
63            }
64        }
65    };
66}
67
68/// Creates a configurable view with builder pattern methods.
69///
70/// This macro generates a wrapper struct and builder methods for configuring views,
71/// following the builder pattern commonly used in UI frameworks.
72///
73/// # Usage
74///
75/// ```ignore
76/// // Default stretch axis (None) - for content-sized views
77/// configurable!(Button, ButtonConfig);
78///
79/// // With explicit stretch axis - for views that expand
80/// configurable!(Slider, SliderConfig, StretchAxis::Horizontal);
81/// configurable!(Color, ColorConfig, StretchAxis::Both);
82///
83/// // With dynamic stretch axis (closure) - for runtime-dependent behavior
84/// configurable!(Progress, ProgressConfig, |config| match config.style {
85///     ProgressStyle::Linear => StretchAxis::Horizontal,
86///     ProgressStyle::Circular => StretchAxis::None,
87/// });
88/// ```
89#[macro_export]
90macro_rules! configurable {
91    // Internal implementation with stretch axis
92    (@impl $(#[$meta:meta])*; $view:ident, $config:ty, $axis:expr) => {
93        $(#[$meta])*
94        pub struct $view($config);
95
96        impl $crate::NativeView for $config {
97            fn stretch_axis(&self) -> $crate::layout::StretchAxis {
98                $axis
99            }
100        }
101
102        impl $crate::view::ConfigurableView for $view {
103            type Config = $config;
104            #[inline] fn config(self) -> Self::Config { self.0 }
105        }
106
107        impl $crate::view::ViewConfiguration for $config {
108            type View = $view;
109            #[inline] fn render(self) -> Self::View { $view(self) }
110        }
111
112        impl From<$config> for $view {
113            #[inline] fn from(value: $config) -> Self { Self(value) }
114        }
115
116        impl $crate::view::View for $view {
117            fn body(self, env: &$crate::Environment) -> impl $crate::View {
118                use $crate::view::ConfigurableView;
119                let config = self.config();
120                if let Some(hook) = env.get::<$crate::view::Hook<$config>>() {
121                    $crate::AnyView::new(hook.apply(env, config))
122                } else {
123                    $crate::AnyView::new($crate::Native::new(config))
124                }
125            }
126
127            fn stretch_axis(&self) -> $crate::layout::StretchAxis {
128                $crate::NativeView::stretch_axis(&self.0)
129            }
130        }
131    };
132
133    // Dynamic stretch axis with closure/function
134    // Internal implementation that generates NativeView with the provided function
135    (@impl_dynamic $(#[$meta:meta])*; $view:ident, $config:ty, $stretch_fn:expr) => {
136        $(#[$meta])*
137        #[derive(Debug)]
138        pub struct $view($config);
139
140        impl $crate::NativeView for $config {
141            fn stretch_axis(&self) -> $crate::layout::StretchAxis {
142                ($stretch_fn)(self)
143            }
144        }
145
146        impl $crate::view::ConfigurableView for $view {
147            type Config = $config;
148            #[inline] fn config(self) -> Self::Config { self.0 }
149        }
150
151        impl $crate::view::ViewConfiguration for $config {
152            type View = $view;
153            #[inline] fn render(self) -> Self::View { $view(self) }
154        }
155
156        impl From<$config> for $view {
157            #[inline] fn from(value: $config) -> Self { Self(value) }
158        }
159
160        impl $crate::view::View for $view {
161            fn body(self, env: &$crate::Environment) -> impl $crate::View {
162                use $crate::view::ConfigurableView;
163                let config = self.config();
164                if let Some(hook) = env.get::<$crate::view::Hook<$config>>() {
165                    $crate::AnyView::new(hook.apply(env, config))
166                } else {
167                    $crate::AnyView::new($crate::Native::new(config))
168                }
169            }
170
171            fn stretch_axis(&self) -> $crate::layout::StretchAxis {
172                $crate::NativeView::stretch_axis(&self.0)
173            }
174        }
175    };
176
177    // Public variant for dynamic stretch_axis with closure: |config| -> StretchAxis
178    // IMPORTANT: This must come BEFORE the $axis:expr variant (closure pattern)
179    ($(#[$meta:meta])* $view:ident, $config:ty, |$param:ident| $body:expr) => {
180        $crate::configurable!(@impl_dynamic $(#[$meta])*; $view, $config, |$param: &$config| $body);
181    };
182
183    // With explicit stretch axis
184    ($(#[$meta:meta])* $view:ident, $config:ty, $axis:expr) => {
185        $crate::configurable!(@impl $(#[$meta])*; $view, $config, $axis);
186    };
187
188    // Default stretch axis (None)
189    ($(#[$meta:meta])* $view:ident, $config:ty) => {
190        $crate::configurable!(@impl $(#[$meta])*; $view, $config, $crate::layout::StretchAxis::None);
191    };
192}
193macro_rules! tuples {
194    ($macro:ident) => {
195        $macro!();
196        $macro!(T0);
197        $macro!(T0, T1);
198        $macro!(T0, T1, T2);
199        $macro!(T0, T1, T2, T3);
200        $macro!(T0, T1, T2, T3, T4);
201        $macro!(T0, T1, T2, T3, T4, T5);
202        $macro!(T0, T1, T2, T3, T4, T5, T6);
203        $macro!(T0, T1, T2, T3, T4, T5, T6, T7);
204        $macro!(T0, T1, T2, T3, T4, T5, T6, T7, T8);
205        $macro!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
206        $macro!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
207        $macro!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
208        $macro!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
209        $macro!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13);
210        $macro!(
211            T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14
212        );
213    };
214}
215
216/// Implements the `Extractor` trait for a type.
217///
218/// This macro generates an implementation that extracts values from the environment
219/// using the `Use<T>` wrapper, commonly used for dependency injection.
220#[macro_export]
221macro_rules! impl_extractor {
222    ($ty:ty) => {
223        impl $crate::extract::Extractor for $ty {
224            fn extract(env: &$crate::Environment) -> core::result::Result<Self, $crate::Error> {
225                $crate::extract::Extractor::extract(env)
226                    .map(|value: $crate::extract::Use<$ty>| value.0)
227            }
228        }
229    };
230}
231
232/// Implements the `Deref` trait for transparent access to an inner type.
233///
234/// This macro generates a `Deref` implementation that allows transparent
235/// access to the inner value of wrapper types.
236#[macro_export]
237macro_rules! impl_deref {
238    ($ty:ty,$target:ty) => {
239        impl core::ops::Deref for $ty {
240            type Target = $target;
241            fn deref(&self) -> &Self::Target {
242                &self.0
243            }
244        }
245
246        impl core::ops::DerefMut for $ty {
247            fn deref_mut(&mut self) -> &mut Self::Target {
248                &mut self.0
249            }
250        }
251    };
252}