lazybar_core/
macros.rs

1/// Defines a struct to hold format strings, along with a constructor.
2///
3/// The constructor has the following function signature:
4/// ```rust,ignore
5/// fn new(value: Vec<T>) -> Self
6/// ```
7/// `value` must have the same number of elements as `args` passed to this
8/// macro, and `new` will panic otherwise.
9#[macro_export]
10macro_rules! array_to_struct {
11    ($name:ident, $($args:ident),+) => {
12        #[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
13        struct $name<T> {
14            $(
15                $args: T,
16            )+
17        }
18
19        impl<T> $name<T> {
20            fn new<const N: usize>(value: [T; N]) -> Self {
21                let mut value = value.into_iter();
22
23                Self {
24                    $(
25                        $args: value.next().unwrap(),
26                    )+
27                }
28            }
29        }
30    };
31}
32
33/// Holds a collection of X atoms, lazily checking their values as they're
34/// retrieved.
35///
36/// The first argument defines the struct name, the second argument should be a
37/// static reference to a struct of this type, and each argument after that is
38/// the name of an atom. The struct has a constructor with signature:
39/// ```rust,ignore
40/// const fn new() -> Self
41/// ```
42/// and a method with signature:
43/// ```rust,ignore
44/// pub fn get(&mut self, conn: &impl Connection, atom_name: &'static str) -> Result<u32>
45/// ```
46/// This macro is for internal use and should be called elsewhere with care.
47#[macro_export]
48macro_rules! interned_atoms {
49    ($name:ident, $ref:expr_2021, $($atoms:ident,)+) => {
50        #[allow(non_snake_case)]
51        #[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
52        pub struct $name {
53            $(
54                $atoms: ::std::primitive::u32,
55            )+
56        }
57
58        impl $name {
59            pub const fn new() -> Self {
60                unsafe { ::std::mem::zeroed() }
61            }
62
63            fn get_inner(
64                &mut self,
65                conn: &impl ::x11rb::connection::Connection,
66                atom_name: &'static ::std::primitive::str,
67            ) -> Result<::std::primitive::u32> {
68                let atom = match atom_name {
69                    $(
70                        stringify!($atoms) => ::std::option::Option::Some(self.$atoms),
71                    )+
72                    _ => ::std::option::Option::None,
73                };
74
75                match atom {
76                    ::std::option::Option::None => ::std::result::Result::Err(::anyhow::anyhow!("Invalid atom name")),
77                    ::std::option::Option::Some(0) => {
78                        let atom =
79                            $crate::x::intern_named_atom(conn, atom_name.as_bytes())?;
80                        match atom_name {
81                            $(
82                                ::std::stringify!($atoms) => self.$atoms = atom,
83                            )+
84                            _ => ::std::unreachable!(),
85                        };
86                        ::std::result::Result::Ok(atom)
87                    }
88                    ::std::option::Option::Some(atom) => ::std::result::Result::Ok(atom),
89                }
90            }
91
92            pub fn get(conn: &impl Connection, atom_name: &'static str) -> Result<u32> {
93                $name::get_inner(&mut *$ref.lock().unwrap(), conn, atom_name)
94            }
95        }
96    };
97}