action.rs

  1use std::any::{Any, TypeId};
  2
  3pub trait Action: 'static {
  4    fn id(&self) -> TypeId;
  5    fn name(&self) -> &'static str;
  6    fn as_any(&self) -> &dyn Any;
  7    fn boxed_clone(&self) -> Box<dyn Action>;
  8
  9    fn qualified_name() -> &'static str
 10    where
 11        Self: Sized;
 12    fn from_json_str(json: &str) -> anyhow::Result<Box<dyn Action>>
 13    where
 14        Self: Sized;
 15}
 16
 17/// Define a set of unit struct types that all implement the `Action` trait.
 18///
 19/// The first argument is a namespace that will be associated with each of
 20/// the given action types, to ensure that they have globally unique
 21/// qualified names for use in keymap files.
 22#[macro_export]
 23macro_rules! actions {
 24    ($namespace:path, [ $($name:ident),* $(,)? ]) => {
 25        $(
 26            #[derive(Clone, Debug, Default, PartialEq, Eq)]
 27            pub struct $name;
 28            $crate::__impl_action! {
 29                $namespace,
 30                $name,
 31                fn from_json_str(_: &str) -> $crate::anyhow::Result<Box<dyn $crate::Action>> {
 32                    Ok(Box::new(Self))
 33                }
 34            }
 35        )*
 36    };
 37}
 38
 39/// Implement the `Action` trait for a set of existing types.
 40///
 41/// The first argument is a namespace that will be associated with each of
 42/// the given action types, to ensure that they have globally unique
 43/// qualified names for use in keymap files.
 44#[macro_export]
 45macro_rules! impl_actions {
 46    ($namespace:path, [ $($name:ident),* $(,)? ]) => {
 47        $(
 48            $crate::__impl_action! {
 49                $namespace,
 50                $name,
 51                fn from_json_str(json: &str) -> $crate::anyhow::Result<Box<dyn $crate::Action>> {
 52                    Ok(Box::new($crate::serde_json::from_str::<Self>(json)?))
 53                }
 54            }
 55        )*
 56    };
 57}
 58
 59/// Implement the `Action` trait for a set of existing types that are
 60/// not intended to be constructed via a keymap file, but only dispatched
 61/// internally.
 62#[macro_export]
 63macro_rules! impl_internal_actions {
 64    ($namespace:path, [ $($name:ident),* $(,)? ]) => {
 65        $(
 66            $crate::__impl_action! {
 67                $namespace,
 68                $name,
 69                fn from_json_str(_: &str) -> $crate::anyhow::Result<Box<dyn $crate::Action>> {
 70                    Err($crate::anyhow::anyhow!("internal action"))
 71                }
 72            }
 73        )*
 74    };
 75}
 76
 77#[doc(hidden)]
 78#[macro_export]
 79macro_rules! __impl_action {
 80    ($namespace:path, $name:ident, $from_json_fn:item) => {
 81        impl $crate::action::Action for $name {
 82            fn name(&self) -> &'static str {
 83                stringify!($name)
 84            }
 85
 86            fn qualified_name() -> &'static str {
 87                concat!(
 88                    stringify!($namespace),
 89                    "::",
 90                    stringify!($name),
 91                )
 92            }
 93
 94            fn id(&self) -> std::any::TypeId {
 95                std::any::TypeId::of::<$name>()
 96            }
 97
 98            fn as_any(&self) -> &dyn std::any::Any {
 99                self
100            }
101
102            fn boxed_clone(&self) -> Box<dyn $crate::Action> {
103                Box::new(self.clone())
104            }
105
106            $from_json_fn
107        }
108    };
109}