wayland_headers/
wayland_util.rs

1use crate::prelude::*;
2
3/// Roughly equivalent to the `wl_array_for_each(pos, array)` C macro.
4///
5/// It can only be invoked inside an `unsafe` block.
6///
7/// The following Rust code:
8///
9/// ```rust
10/// let a: *const wl_array = /*...*/;
11/// unsafe {
12///     wl_array_for_each!(p: *mut c_int, a, {
13///         // ...
14///     });
15/// }
16/// ```
17///
18/// is roughly equivalent to the following C code:
19///
20/// ```c
21/// const struct wl_array *a = /*...*/;
22/// int *p;
23/// wl_array_for_each(p, a) {
24///     // ...
25/// }
26/// ```
27#[macro_export]
28macro_rules! wl_array_for_each {
29    ($pos:ident: *const $T:ty, $array:expr, $body:block) => {
30        for $pos in $crate::_macro_helpers::WlArrayForEachIter::<$T>::new($array) {
31            let $pos = $pos.as_ptr().cast_const();
32            $body
33        }
34    };
35    ($pos:ident: *mut $T:ty, $array:expr, $body:block) => {
36        for $pos in $crate::_macro_helpers::WlArrayForEachIter::<$T>::new($array) {
37            let $pos = $pos.as_ptr();
38            $body
39        }
40    };
41}
42pub use wl_array_for_each;
43
44/// Roughly equivalent to the `wl_container_of(ptr, sample, member)` C macro.
45///
46/// This version requires a pointer type to the container type as the second argument,
47/// unlike the C version which takes a sample expression.
48///
49/// It can only be invoked inside an `unsafe` block.
50#[macro_export]
51macro_rules! wl_container_of {
52    ($ptr:expr, *const $Container:ty, $member:ident) => {{
53        let ptr: *const _ = $ptr;
54        let ptr = ptr.cast::<$crate::_macro_helpers::u8>();
55        let offset = $crate::_macro_helpers::offset_of!($Container, $member);
56        ptr.sub(offset).cast::<$Container>()
57    }};
58    ($ptr:expr, *mut $Container:ty, $member:ident) => {{
59        let ptr: *const _ = $ptr;
60        let ptr = ptr.cast::<$crate::_macro_helpers::u8>();
61        let offset = $crate::_macro_helpers::offset_of!($Container, $member);
62        ptr.sub(offset).cast::<$Container>().cast_mut()
63    }};
64}
65pub use wl_container_of;
66
67/// Roughly equivalent to the `wl_list_for_each(pos, head, member)` C macro.
68///
69/// It can only be invoked inside an `unsafe` block.
70///
71/// The following Rust code:
72///
73/// ```rust
74/// struct message {
75///     contents: *mut c_char,
76///     link: wl_list,
77/// }
78///
79/// let message_list: *const wl_list = /*...*/;
80/// unsafe {
81///     wl_list_for_each!(m: *mut message, message_list, link, {
82///         // ...
83///     });
84/// }
85/// ```
86///
87/// is roughly equivalent to the following C code:
88///
89/// ```c
90/// struct message {
91///     char *contents;
92///     struct wl_list link;
93/// }
94///
95/// const struct wl_list *message_list = /*...*/;
96/// struct message *m;
97/// wl_list_for_each(m, message_list, link) {
98///     // ...
99/// }
100/// ```
101#[macro_export]
102macro_rules! wl_list_for_each {
103    ($pos:ident: *const $T:ty, $head:expr, $member:ident, $body:block) => {
104        for $pos in $crate::_macro_helpers::WlListForEachIter::new($head) {
105            let $pos = $crate::wl_container_of!($pos.as_ptr(), *const $T, $member);
106            $body
107        }
108    };
109    ($pos:ident: *mut $T:ty, $head:expr, $member:ident, $body:block) => {
110        for $pos in $crate::_macro_helpers::WlListForEachIter::new($head) {
111            let $pos = $crate::wl_container_of!($pos.as_ptr(), *mut $T, $member);
112            $body
113        }
114    };
115}
116pub use wl_list_for_each;
117
118/// Roughly equivalent to the `wl_list_for_each_reverse(pos, head, member)` C macro.
119///
120/// It can only be invoked inside an `unsafe` block.
121///
122/// The following Rust code:
123///
124/// ```rust
125/// struct message {
126///     contents: *mut c_char,
127///     link: wl_list,
128/// }
129///
130/// let message_list: *const wl_list = /*...*/;
131/// unsafe {
132///     wl_list_for_each_reverse!(m: *mut message, message_list, link, {
133///         // ...
134///     });
135/// }
136/// ```
137///
138/// is roughly equivalent to the following C code:
139///
140/// ```c
141/// struct message {
142///     char *contents;
143///     struct wl_list link;
144/// }
145///
146/// const struct wl_list *message_list = /*...*/;
147/// struct message *m;
148/// wl_list_for_each_reverse(m, message_list, link) {
149///     // ...
150/// }
151/// ```
152#[macro_export]
153macro_rules! wl_list_for_each_reverse {
154    ($pos:ident: *const $T:ty, $head:expr, $member:ident, $body:block) => {
155        for $pos in $crate::_macro_helpers::WlListForEachReverseIter::new($head) {
156            let $pos = $crate::wl_container_of!($pos.as_ptr(), *const $T, $member);
157            $body
158        }
159    };
160    ($pos:ident: *mut $T:ty, $head:expr, $member:ident, $body:block) => {
161        for $pos in $crate::_macro_helpers::WlListForEachReverseIter::new($head) {
162            let $pos = $crate::wl_container_of!($pos.as_ptr(), *mut $T, $member);
163            $body
164        }
165    };
166}
167pub use wl_list_for_each_reverse;
168
169/// Roughly equivalent to the `wl_list_for_each_reverse_safe(pos, tmp, head, member)` C macro.
170///
171/// This version does not require a `tmp` argument, unlike the C version.
172///
173/// It can only be invoked inside an `unsafe` block.
174///
175/// The following Rust code:
176///
177/// ```rust
178/// struct message {
179///     contents: *mut c_char,
180///     link: wl_list,
181/// }
182///
183/// let message_list: *const wl_list = /*...*/;
184/// unsafe {
185///     wl_list_for_each_reverse_safe!(m: *mut message, message_list, link, {
186///         // ...
187///     });
188/// }
189/// ```
190///
191/// is roughly equivalent to the following C code:
192///
193/// ```c
194/// struct message {
195///     char *contents;
196///     struct wl_list link;
197/// }
198///
199/// const struct wl_list *message_list = /*...*/;
200/// struct message *m, tmp;
201/// wl_list_for_each_reverse_safe(m, tmp, message_list, link) {
202///     // ...
203/// }
204/// ```
205#[macro_export]
206macro_rules! wl_list_for_each_reverse_safe {
207    ($pos:ident: *const $T:ty, $head:expr, $member:ident, $body:block) => {
208        for $pos in $crate::_macro_helpers::WlListForEachReverseSafeIter::new($head) {
209            let $pos = $crate::wl_container_of!($pos.as_ptr(), *const $T, $member);
210            $body
211        }
212    };
213    ($pos:ident: *mut $T:ty, $head:expr, $member:ident, $body:block) => {
214        for $pos in $crate::_macro_helpers::WlListForEachReverseSafeIter::new($head) {
215            let $pos = $crate::wl_container_of!($pos.as_ptr(), *mut $T, $member);
216            $body
217        }
218    };
219}
220pub use wl_list_for_each_reverse_safe;
221
222/// Roughly equivalent to the `wl_list_for_each_safe(pos, tmp, head, member)` C macro.
223///
224/// This version does not require a `tmp` argument, unlike the C version.
225///
226/// It can only be invoked inside an `unsafe` block.
227///
228/// The following Rust code:
229///
230/// ```rust
231/// struct message {
232///     contents: *mut c_char,
233///     link: wl_list,
234/// }
235///
236/// let message_list: *const wl_list = /*...*/;
237/// unsafe {
238///     wl_list_for_each_safe!(m: *mut message, message_list, link, {
239///         // ...
240///     });
241/// }
242/// ```
243///
244/// is roughly equivalent to the following C code:
245///
246/// ```c
247/// struct message {
248///     char *contents;
249///     struct wl_list link;
250/// }
251///
252/// const struct wl_list *message_list = /*...*/;
253/// struct message *m, tmp;
254/// wl_list_for_each_safe(m, tmp, message_list, link) {
255///     // ...
256/// }
257/// ```
258#[macro_export]
259macro_rules! wl_list_for_each_safe {
260    ($pos:ident: *const $T:ty, $head:expr, $member:ident, $body:block) => {
261        for $pos in $crate::_macro_helpers::WlListForEachSafeIter::new($head) {
262            let $pos = $crate::wl_container_of!($pos.as_ptr(), *const $T, $member);
263            $body
264        }
265    };
266    ($pos:ident: *mut $T:ty, $head:expr, $member:ident, $body:block) => {
267        for $pos in $crate::_macro_helpers::WlListForEachSafeIter::new($head) {
268            let $pos = $crate::wl_container_of!($pos.as_ptr(), *mut $T, $member);
269            $body
270        }
271    };
272}
273pub use wl_list_for_each_safe;
274
275#[derive(Clone, Copy)]
276#[repr(C)]
277pub struct wl_array {
278    pub size: usize,
279    pub alloc: usize,
280    pub data: *mut c_void,
281}
282
283#[derive(Clone, Copy)]
284#[repr(C)]
285pub struct wl_interface {
286    pub name: *const c_char,
287    pub version: c_int,
288    pub method_count: c_int,
289    pub methods: *const wl_message,
290    pub event_count: c_int,
291    pub events: *const wl_message,
292}
293
294#[derive(Clone, Copy)]
295#[repr(C)]
296pub struct wl_list {
297    pub prev: *mut wl_list,
298    pub next: *mut wl_list,
299}
300
301#[derive(Clone, Copy)]
302#[repr(C)]
303pub struct wl_message {
304    pub name: *const c_char,
305    pub signature: *const c_char,
306    pub types: *mut *const wl_interface,
307}
308
309#[repr(C)]
310pub struct wl_object {
311    _data: (),
312    _marker: PhantomData<(*mut u8, PhantomPinned)>,
313}
314
315pub const WL_ITERATOR_CONTINUE: wl_iterator_result = 1;
316pub const WL_ITERATOR_STOP: wl_iterator_result = 0;
317
318unsafe extern "C" {
319    pub fn wl_array_add(array: *mut wl_array, size: usize) -> *mut c_void;
320
321    pub fn wl_array_copy(array: *mut wl_array, source: *mut wl_array) -> c_int;
322
323    pub fn wl_array_init(array: *mut wl_array);
324
325    pub fn wl_array_release(array: *mut wl_array);
326}
327
328#[inline]
329pub extern "C" fn wl_fixed_from_double(d: c_double) -> wl_fixed_t {
330    let d = d + ((3i64 << (51 - 8)) as c_double);
331    d.to_bits() as wl_fixed_t
332}
333
334#[inline]
335pub extern "C" fn wl_fixed_from_int(i: c_int) -> wl_fixed_t {
336    i * 256
337}
338
339#[inline]
340pub extern "C" fn wl_fixed_to_double(f: wl_fixed_t) -> c_double {
341    let i = ((1023i64 + 44i64) << 52) + (1i64 << 51) + (f as i64);
342    c_double::from_bits(i as u64) - ((3i64 << 43) as c_double)
343}
344
345#[inline]
346pub extern "C" fn wl_fixed_to_int(f: wl_fixed_t) -> c_int {
347    f / 256
348}
349
350unsafe extern "C" {
351    pub fn wl_list_empty(list: *const wl_list) -> c_int;
352
353    pub fn wl_list_init(list: *mut wl_list);
354
355    pub fn wl_list_insert(list: *mut wl_list, elm: *mut wl_list);
356
357    pub fn wl_list_insert_list(list: *mut wl_list, other: *mut wl_list);
358
359    pub fn wl_list_length(list: *const wl_list) -> c_int;
360
361    pub fn wl_list_remove(elm: *mut wl_list);
362}
363
364pub type wl_dispatcher_func_t = Option<
365    unsafe extern "C" fn(
366        _: *const c_void,
367        _: *mut c_void,
368        _: u32,
369        _: *const wl_message,
370        _: *mut wl_argument,
371    ) -> c_int,
372>;
373
374pub type wl_fixed_t = i32;
375pub type wl_iterator_result = c_int;
376
377pub type wl_log_func_t = Option<
378    unsafe extern "C" fn(
379        _: *const c_char,
380        _: *mut c_void, // TODO: VaList
381    ),
382>;
383
384#[repr(C)]
385pub union wl_argument {
386    pub i: i32,
387    pub u: u32,
388    pub f: wl_fixed_t,
389    pub s: *const c_char,
390    pub o: *mut wl_object,
391    pub n: u32,
392    pub a: *mut wl_array,
393    pub h: i32,
394}
395
396#[cfg(test)]
397mod tests {
398    use core::{mem::MaybeUninit, ptr::null_mut};
399
400    use super::*;
401
402    #[link(name = "wayland-client")]
403    unsafe extern "C" {}
404
405    struct Foo {
406        _m: i32,
407        link: wl_list,
408    }
409
410    impl Foo {
411        fn new() -> Self {
412            Self {
413                _m: 0,
414                link: wl_list {
415                    prev: null_mut(),
416                    next: null_mut(),
417                },
418            }
419        }
420    }
421
422    #[test]
423    fn test_wl_array_for_each() {
424        unsafe {
425            let mut array = MaybeUninit::uninit();
426            wl_array_init(array.as_mut_ptr());
427            let data = wl_array_add(array.as_mut_ptr(), size_of::<Foo>() * 3);
428
429            let mut i = 0;
430            wl_array_for_each!(foo: *const Foo, array.as_ptr(), {
431                assert!(i < 3);
432                assert_eq!(foo, data.cast::<Foo>().add(i));
433                i += 1;
434            });
435            assert_eq!(i, 3);
436
437            let mut i = 0;
438            wl_array_for_each!(foo: *mut Foo, array.as_ptr(), {
439                assert!(i < 3);
440                assert_eq!(foo, data.cast::<Foo>().add(i));
441                i += 1;
442            });
443            assert_eq!(i, 3);
444
445            wl_array_release(array.as_mut_ptr());
446        }
447    }
448
449    #[test]
450    fn test_wl_container_of() {
451        let mut foo = Foo::new();
452        assert_eq!(
453            unsafe { wl_container_of!(&foo.link, *const Foo, link) },
454            &raw const foo
455        );
456        assert_eq!(
457            unsafe { wl_container_of!(&foo.link, *mut Foo, link) },
458            &raw mut foo
459        );
460    }
461
462    fn with_test_list<F>(f: F)
463    where
464        F: FnOnce(&mut wl_list, [&mut Foo; 3]),
465    {
466        unsafe {
467            let mut list = MaybeUninit::uninit();
468            wl_list_init(list.as_mut_ptr());
469            let list = &mut *list.as_mut_ptr();
470
471            let mut e1 = Foo::new();
472            wl_list_insert(list, &mut e1.link);
473
474            let mut e2 = Foo::new();
475            wl_list_insert(&mut e1.link, &mut e2.link);
476
477            let mut e3 = Foo::new();
478            wl_list_insert(&mut e2.link, &mut e3.link);
479
480            f(list, [&mut e1, &mut e2, &mut e3]);
481        }
482    }
483
484    #[test]
485    fn test_wl_list_for_each() {
486        with_test_list(|list, elems| unsafe {
487            let mut i = 0;
488            wl_list_for_each!(foo: *const Foo, list, link, {
489                assert_eq!(foo, elems[i] as *const _);
490                i += 1;
491            });
492            assert_eq!(i, 3);
493
494            let mut i = 0;
495            wl_list_for_each!(foo: *mut Foo, list, link, {
496                assert_eq!(foo, elems[i] as *mut _);
497                i += 1;
498            });
499            assert_eq!(i, 3);
500        });
501    }
502
503    #[test]
504    fn test_wl_list_for_each_reverse() {
505        with_test_list(|list, elems| unsafe {
506            let mut i = elems.len();
507            wl_list_for_each_reverse!(foo: *const Foo, list, link, {
508                i -= 1;
509                assert_eq!(foo, elems[i] as *const _);
510            });
511            assert_eq!(i, 0);
512
513            let mut i = elems.len();
514            wl_list_for_each_reverse!(foo: *mut Foo, list, link, {
515                i -= 1;
516                assert_eq!(foo, elems[i] as *mut _);
517            });
518            assert_eq!(i, 0);
519        });
520    }
521
522    #[test]
523    fn test_wl_list_for_each_reverse_safe() {
524        with_test_list(|list, elems| unsafe {
525            let mut i = elems.len();
526            wl_list_for_each_reverse_safe!(foo: *const Foo, list, link, {
527                i -= 1;
528                assert_eq!(foo, elems[i] as *const _);
529            });
530            assert_eq!(i, 0);
531
532            let mut i = elems.len();
533            wl_list_for_each_reverse_safe!(foo: *mut Foo, list, link, {
534                i -= 1;
535                assert_eq!(foo, elems[i] as *mut _);
536                wl_list_remove(&raw mut (*foo).link);
537            });
538            assert_eq!(i, 0);
539        });
540    }
541
542    #[test]
543    fn test_wl_list_for_each_safe() {
544        with_test_list(|list, elems| unsafe {
545            let mut i = 0;
546            wl_list_for_each_safe!(foo: *const Foo, list, link, {
547                assert_eq!(foo, elems[i] as *const _);
548                i += 1;
549            });
550            assert_eq!(i, 3);
551
552            let mut i = 0;
553            wl_list_for_each_safe!(foo: *mut Foo, list, link, {
554                assert_eq!(foo, elems[i] as *mut _);
555                wl_list_remove(&raw mut (*foo).link);
556                i += 1;
557            });
558            assert_eq!(i, 3);
559        });
560    }
561}