Skip to main content

xray_tui/tui/view/
macros.rs

1#[macro_export]
2macro_rules! render_order_enum {
3    ( $name:ident, $( $variant:ident ),+ ) => {
4        /// Represents the currently active element and the order in which this set of elements is rendered.
5        ///
6        /// The order in which variants are defined represents the order in which the corresponding elements will be rendered.
7        #[derive(::formatted_index_macro::FormattedIndex, Debug, Default, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
8        pub enum $name {
9            #[default]
10            $(
11                $variant,
12            )*
13        }
14
15        impl From<$name> for usize {
16            fn from(value: $name) -> Self {
17                match value {
18                    $(
19                      $name::$variant => ${index()},
20                    )*
21                }
22            }
23        }
24
25        impl TryFrom<usize> for $name {
26            type Error = anyhow::Error;
27
28            fn try_from(value: usize) -> Result<Self, Self::Error> {
29                Ok(match value {
30                    $(
31                        ${index()} => $name::$variant,
32                    )*
33                    _ => anyhow::bail!("no matching variant of {} found for the provided index", stringify!($name)),
34                })
35            }
36        }
37
38        impl $name {
39            const NUMBER_OF_FIELDS: usize = ${count($variant)};
40
41            pub fn toggle(&mut self, direction: $crate::tui::action::Direction) {
42                let current_variant_idx = Into::<usize>::into(*self);
43
44                let next_variant_idx = match direction {
45                    $crate::tui::action::Direction::Forward => (current_variant_idx + 1) % Self::NUMBER_OF_FIELDS,
46                    $crate::tui::action::Direction::Backward => (current_variant_idx + Self::NUMBER_OF_FIELDS - 1) % Self::NUMBER_OF_FIELDS,
47                };
48
49                if let Ok(next_variant) = $name::try_from(next_variant_idx) {
50                    *self = next_variant;
51                } else {
52                    // This is pretty much unreacheable, as macro ensures that the `next_variant_idx` is always valid.
53                    // Still, I don't want the app to panic in this case. A simple log is enough.
54                    tracing::debug!("Failed to toggle the currently active element for {}. Unknown index: {}", stringify!($name), next_variant_idx);
55                }
56            }
57
58            pub fn select(&mut self, index: usize) -> anyhow::Result<()> {
59                let new_active_pane = anyhow::Context::<Self, anyhow::Error>::with_context(
60                    TryFrom::<usize>::try_from(index),
61                    || format!("failed to convert the provided index into an instance of {}", stringify!($name))
62                )?;
63                *self = new_active_pane;
64
65                Ok(())
66            }
67        }
68    };
69}
70
71#[macro_export]
72macro_rules! sort_fields_by_render_order {
73    ( $order_enum:ident ) => {
74        impl $order_enum {
75            fn sort_fields_by_order(
76                fields: &mut [$crate::tui::view::pane::util::Field<
77                    '_,
78                    $order_enum,
79                >],
80            ) {
81                fields.sort_by(|(a, _), (b, _)| a.cmp(b))
82            }
83        }
84    };
85}