Files
osui/src/macros.rs
T

200 lines
6.0 KiB
Rust

#[macro_export]
macro_rules! event {
($name:ident) => {
#[derive(Debug, Clone)]
pub struct $name;
impl $crate::extensions::Event for $name {
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
};
($name:ident {$($inner:tt)*}) => {
#[derive(Debug, Clone)]
pub struct $name {
$($inner)*
}
impl $crate::extensions::Event for $name {
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
};
($name:ident ($($inner:tt)*)) => {
#[derive(Debug, Clone)]
pub struct $name ($($inner)*);
impl $crate::extensions::Event for $name {
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
};
}
#[macro_export]
macro_rules! component {
($name:ident) => {
#[derive(Debug, Clone)]
pub struct $name;
impl $crate::widget::Component for $name {
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
}
};
($name:ident {$($inner:tt)*}) => {
#[derive(Debug, Clone)]
pub struct $name {
$($inner)*
}
impl $crate::widget::Component for $name {
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
}
};
($name:ident ($($inner:tt)*)) => {
#[derive(Debug, Clone)]
pub struct $name ($($inner)*);
impl $crate::widget::Component for $name {
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
}
};
}
/// Macro to create an event handler closure that calls a method on `self`
///
/// This macro automates the pattern of capturing `self` as a raw pointer,
/// then passing an event to a method on `self` inside an unsafe closure.
///
/// # Parameters
/// - `$self_ty`: The self type.
/// - `$self`: The instance variable (usually `self`) to call the method on.
/// - `$events`: The event source which has an `.on` method to register the handler.
/// - `$method`: The method name on `self` to call when an event occurs.
///
/// # Usage
/// ```rust
/// event_handler!(self, events, on_keypress);
/// ```
///
/// This expands roughly to:
/// ```rust
/// let self_ref = self as *mut Self;
/// events.on(move |event| unsafe { (*self_ref).on_keypress(event) });
/// ```
///
/// # Safety
/// This macro uses `unsafe` code because it dereferences a raw pointer inside the closure.
/// Ensure that the `self` reference lives at least as long as the closure to avoid undefined behavior.
///
/// # Why use raw pointers here?
/// Often, event handlers require `'static` closures, but `self` is a stack reference.
/// Capturing `self` directly is not possible, so this workaround uses a raw pointer.
#[macro_export]
macro_rules! event_handler {
($self_ty:ty, $self:ident, $events:ident, $method:ident) => {{
let self_ref = $self as *mut $self_ty;
$events.on(move |es, e| unsafe { (*self_ref).$method(es, e) });
}};
}
#[macro_export]
macro_rules! transform {
($($f:ident: $v:expr),* $(,)?) => {{
let mut t = Transform::new();
$(t.$f = $v.into();)*
t
}};
}
#[macro_export]
macro_rules! rsx {
($($inner:tt)*) => {{
let mut r = $crate::frontend::Rsx(Vec::new());
$crate::rsx_inner! { r, $($inner)* };
r
}};
}
#[macro_export]
macro_rules! rsx_inner {
// static
($r:expr, $(@$comp:expr;)* static $s:literal $($rest:tt)*) => {
let w = $crate::widget::StaticWidget::new(Box::new(format!($s)));
$(w.component($comp);)*
$r.create_element_static(w, $crate::frontend::Rsx(Vec::new()));
$crate::rsx_inner! { $r, $($rest)* };
};
($r:expr, $(@$comp:expr;)* $(%$dep:ident)* $s:literal $($rest:tt)*) => {
$r.create_element({ $(let $dep = $dep.clone();)* move || {
$crate::widget::WidgetLoad::new(format!($s)) $(.component($comp))*
} }, vec![$(Box::new($dep.clone())),*], $crate::frontend::Rsx(Vec::new()));
$crate::rsx_inner! { $r, $($rest)* };
};
// static
($r:expr, $(@$comp:expr;)* static $name:path { $($inner:tt)* } ($($e:expr),*) $($rest:tt)*) => {
let w = $crate::widget::StaticWidget::new(Box::new(<$name>::new($($e),*)));
$(w.component($comp);)*
$r.create_element_static(w, $crate::frontend::Rsx(Vec::new()));
$crate::rsx_inner! { $r, $($rest)* };
};
// static
($r:expr, $(@$comp:expr;)* static $name:path { $($inner:tt)* } $($rest:tt)*) => {
let w = $crate::widget::StaticWidget::new(Box::new(<$name>::new()));
$(w.component($comp);)*
$r.create_element_static(w, $crate::frontend::Rsx(Vec::new()));
$crate::rsx_inner! { $r, $($rest)* };
};
($r:expr, $(@$comp:expr;)* $(%$dep:ident)* $name:path { $($inner:tt)* } ($($e:expr),*) $($rest:tt)*) => {
$r.create_element({ $(let $dep = $dep.clone();)* move || {
$crate::widget::WidgetLoad::new(<$name>::new($($e),*)) $(.component($comp))*
} }, vec![$(Box::new($dep.clone())),*], $crate::rsx!{ $($inner)* });
$crate::rsx_inner! { $r, $($rest)* };
};
($r:expr, $(@$comp:expr;)* $(%$dep:ident)* $name:path { $($inner:tt)* } $($rest:tt)*) => {
$r.create_element({ $(let $dep = $dep.clone();)* move || {
$crate::widget::WidgetLoad::new(<$name>::new()) $(.component($comp))*
} }, vec![$(Box::new($dep.clone())),*], $crate::rsx!{ $($inner)* });
$crate::rsx_inner! { $r, $($rest)* };
};
($r:expr, $expand:ident => ($($inner:tt)*) $($rest:tt)*) => {
$r.expand(&mut $expand($($inner)*));
$crate::rsx_inner! { $r, $($rest)* };
};
($r:expr,) => {};
}