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
pub enum VarArg<'a> {
I32(i32),
I32Out(&'a mut i32),
U32Out(&'a mut u32),
F32Ptr(*mut f32),
U8Ptr(*mut u8),
CustomModeOut(&'a mut *const crate::OpusCustomMode),
OpusDecoderOut(&'a mut *mut crate::OpusDecoder),
OpusEncoderOut(&'a mut *mut crate::OpusEncoder),
AnalysisInfoOut(&'a mut crate::src::analysis::AnalysisInfo),
SilkInfoOut(&'a mut crate::celt::celt_encoder::SILKInfo),
}
pub trait FromVarArg<'a> {
fn from_vararg(arg: VarArg<'a>) -> Self;
}
pub trait IntoVarArg<'a> {
fn into_vararg(self) -> VarArg<'a>;
}
macro_rules! impl_from_vararg {
($t:ty, $v:ident) => {
impl<'a> FromVarArg<'a> for $t {
fn from_vararg(arg: VarArg<'a>) -> Self {
match arg {
VarArg::$v(v) => v,
_ => panic!("invalid vararg type"),
}
}
}
};
}
macro_rules! impl_into_vararg {
($t:ty, $v:ident) => {
impl<'a> IntoVarArg<'a> for $t {
fn into_vararg(self) -> VarArg<'a> {
VarArg::$v(self)
}
}
};
}
macro_rules! impl_vararg {
($t:ty, $v:ident) => {
impl_from_vararg!($t, $v);
impl_into_vararg!($t, $v);
};
}
impl_vararg!(i32, I32);
impl_vararg!(&'a mut i32, I32Out);
impl_vararg!(&'a mut u32, U32Out);
impl_vararg!(*mut f32, F32Ptr);
impl_vararg!(*mut u8, U8Ptr);
impl_vararg!(&'a mut *const crate::OpusCustomMode, CustomModeOut);
impl_vararg!(&'a mut *mut crate::OpusDecoder, OpusDecoderOut);
impl_vararg!(&'a mut *mut crate::OpusEncoder, OpusEncoderOut);
impl_vararg!(&'a mut crate::src::analysis::AnalysisInfo, AnalysisInfoOut);
impl_vararg!(&'a mut crate::celt::celt_encoder::SILKInfo, SilkInfoOut);
pub struct VarArgs<'a>(Vec<VarArg<'a>>);
impl<'a> VarArgs<'a> {
pub fn new(mut varargs: Vec<VarArg<'a>>) -> Self {
varargs.reverse();
Self(varargs)
}
pub fn arg<T: FromVarArg<'a>>(&mut self) -> T {
T::from_vararg(
self.0
.pop()
.expect("Attempt to pop from empty varargs (are the function arguments correct?)"),
)
}
}
#[macro_export]
macro_rules! varargs {
($($arg:expr),*) => {
$crate::varargs::VarArgs::new(
vec![
$(
$crate::varargs::IntoVarArg::into_vararg($arg)
),*
]
)
};
}