lazybar_core/
macros.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/// Defines a struct to hold format strings, along with a constructor.
///
/// The constructor has the following function signature:
/// ```rust,ignore
/// fn new(value: Vec<T>) -> Self
/// ```
/// `value` must have the same number of elements as `args` passed to this
/// macro, and `new` will panic otherwise.
#[macro_export]
macro_rules! array_to_struct {
    ($name:ident, $($args:ident),+) => {
        #[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
        struct $name<T> {
            $(
                $args: T,
            )+
        }

        impl<T> $name<T> {
            fn new<const N: usize>(value: [T; N]) -> Self {
                let mut value = value.into_iter();

                Self {
                    $(
                        $args: value.next().unwrap(),
                    )+
                }
            }
        }
    };
}

/// Holds a collection of X atoms, lazily checking their values as they're
/// retrieved.
///
/// The first argument defines the struct name, the second argument should be a
/// static reference to a struct of this type, and each argument after that is
/// the name of an atom. The struct has a constructor with signature:
/// ```rust,ignore
/// const fn new() -> Self
/// ```
/// and a method with signature:
/// ```rust,ignore
/// pub fn get(&mut self, conn: &impl Connection, atom_name: &'static str) -> Result<u32>
/// ```
/// This macro is for internal use and should be called elsewhere with care.
#[macro_export]
macro_rules! interned_atoms {
    ($name:ident, $ref:expr, $($atoms:ident,)+) => {
        #[allow(non_snake_case)]
        #[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
        pub struct $name {
            $(
                $atoms: ::std::primitive::u32,
            )+
        }

        impl $name {
            pub const fn new() -> Self {
                unsafe { ::std::mem::zeroed() }
            }

            fn get_inner(
                &mut self,
                conn: &impl ::x11rb::connection::Connection,
                atom_name: &'static ::std::primitive::str,
            ) -> Result<::std::primitive::u32> {
                let atom = match atom_name {
                    $(
                        stringify!($atoms) => ::std::option::Option::Some(self.$atoms),
                    )+
                    _ => ::std::option::Option::None,
                };

                match atom {
                    ::std::option::Option::None => ::std::result::Result::Err(::anyhow::anyhow!("Invalid atom name")),
                    ::std::option::Option::Some(0) => {
                        let atom =
                            $crate::x::intern_named_atom(conn, atom_name.as_bytes())?;
                        match atom_name {
                            $(
                                ::std::stringify!($atoms) => self.$atoms = atom,
                            )+
                            _ => ::std::unreachable!(),
                        };
                        ::std::result::Result::Ok(atom)
                    }
                    ::std::option::Option::Some(atom) => ::std::result::Result::Ok(atom),
                }
            }

            pub fn get(conn: &impl Connection, atom_name: &'static str) -> Result<u32> {
                $name::get_inner(&mut *$ref.lock().unwrap(), conn, atom_name)
            }
        }
    };
}