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}