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
use core::ffi::c_void;
use core::iter::zip;
use core::ops::{BitOrAssign, Shl};
use core::ptr::NonNull;

use std::collections::HashSet;

use anyhow::Context as _;

#[repr(C)]
#[derive(Debug)]
pub struct List<T> {
    pub ptr: *const T,
    pub len: usize,
}

pub fn flag_bits<'a, T: BitOrAssign + Shl<u8, Output = T> + From<u8>>(
    names: impl IntoIterator<Item = &'a str>,
    flags: impl IntoIterator<Item = &'a str>,
) -> T {
    let mut v = T::from(0);
    let flags: HashSet<&str> = flags.into_iter().collect();
    for (i, name) in zip(0u8.., names) {
        if flags.contains(name) {
            v |= T::from(1) << i;
        }
    }
    v
}

pub fn find_enum_discriminant<'a, T>(
    iter: impl IntoIterator<Item = T>,
    names: impl IntoIterator<Item = &'a str>,
    disc: &str,
) -> anyhow::Result<T> {
    zip(iter, names)
        .find_map(|(i, name)| (name == disc).then_some(i))
        .context("unknown enum discriminant")
}

pub fn deref_arg<T>(args: *const *mut c_void) -> anyhow::Result<(NonNull<T>, *const *mut c_void)> {
    let args: NonNull<*mut c_void> =
        NonNull::new(args.cast_mut()).context("argument cannot be null")?;
    let data = unsafe { args.read() };
    let data = NonNull::new(data.cast()).context("value cannot be null")?;
    Ok((data, args.as_ptr().wrapping_add(1)))
}