unsafe_libopus/
varargs.rs

1//! A bit more type-safe variadic function APIs. Not really ABI-compatible with C, just a compat layer.
2
3pub enum VarArg<'a> {
4    I32(i32),
5    I32Out(&'a mut i32),
6    U32Out(&'a mut u32),
7    F32Ptr(*mut f32),
8    U8Ptr(*mut u8),
9    CustomModeOut(&'a mut *const crate::OpusCustomMode),
10    OpusDecoderOut(&'a mut *mut crate::OpusDecoder),
11    OpusEncoderOut(&'a mut *mut crate::OpusEncoder),
12    AnalysisInfoOut(&'a mut crate::src::analysis::AnalysisInfo),
13    SilkInfoOut(&'a mut crate::celt::celt_encoder::SILKInfo),
14}
15
16pub trait FromVarArg<'a> {
17    fn from_vararg(arg: VarArg<'a>) -> Self;
18}
19
20pub trait IntoVarArg<'a> {
21    fn into_vararg(self) -> VarArg<'a>;
22}
23
24macro_rules! impl_from_vararg {
25    ($t:ty, $v:ident) => {
26        impl<'a> FromVarArg<'a> for $t {
27            fn from_vararg(arg: VarArg<'a>) -> Self {
28                match arg {
29                    VarArg::$v(v) => v,
30                    _ => panic!("invalid vararg type"),
31                }
32            }
33        }
34    };
35}
36macro_rules! impl_into_vararg {
37    ($t:ty, $v:ident) => {
38        impl<'a> IntoVarArg<'a> for $t {
39            fn into_vararg(self) -> VarArg<'a> {
40                VarArg::$v(self)
41            }
42        }
43    };
44}
45macro_rules! impl_vararg {
46    ($t:ty, $v:ident) => {
47        impl_from_vararg!($t, $v);
48        impl_into_vararg!($t, $v);
49    };
50}
51
52impl_vararg!(i32, I32);
53impl_vararg!(&'a mut i32, I32Out);
54impl_vararg!(&'a mut u32, U32Out);
55impl_vararg!(*mut f32, F32Ptr);
56impl_vararg!(*mut u8, U8Ptr);
57impl_vararg!(&'a mut *const crate::OpusCustomMode, CustomModeOut);
58impl_vararg!(&'a mut *mut crate::OpusDecoder, OpusDecoderOut);
59impl_vararg!(&'a mut *mut crate::OpusEncoder, OpusEncoderOut);
60impl_vararg!(&'a mut crate::src::analysis::AnalysisInfo, AnalysisInfoOut);
61impl_vararg!(&'a mut crate::celt::celt_encoder::SILKInfo, SilkInfoOut);
62
63pub struct VarArgs<'a>(pub Vec<VarArg<'a>>);
64
65impl<'a> VarArgs<'a> {
66    pub fn new(mut varargs: Vec<VarArg<'a>>) -> Self {
67        // reverse them, because we pop them off the end, but want to have order "from left to right"
68        varargs.reverse();
69        Self(varargs)
70    }
71
72    pub fn arg<T: FromVarArg<'a>>(&mut self) -> T {
73        T::from_vararg(
74            self.0
75                .pop()
76                .expect("Attempt to pop from empty varargs (are the function arguments correct?)"),
77        )
78    }
79}
80
81#[macro_export]
82macro_rules! varargs {
83    ($($arg:expr),*) => {
84        $crate::varargs::VarArgs::new(
85            vec![
86                $(
87                    $crate::varargs::IntoVarArg::into_vararg($arg)
88                ),*
89            ]
90        )
91    };
92}