va_list/
lib.rs

1#![allow(dead_code)]
2
3extern crate libc;
4
5/// This macro is the only thing provided by this crate.
6///
7/// ## Arguments
8///
9/// It expects a closure as first argument and then the arguments
10/// that'll be used to build the `va_list`.
11///
12/// ## Example
13///
14/// ```ignore
15/// unsafe {
16///     to_va_list!(|v: va_list::va_list| {
17///         vprintf(b"%d %d %s %f\n\0".as_ptr() as *const c_char, v);
18///     },
19///     1, 2, b"salut!\0".as_ptr(), 32f32 as c_double);
20/// }
21/// ```
22///
23/// ## Warning
24///
25/// It might exist a limit to the number of arguments you can actually pass.
26/// A big one, but don't try to send thousands of them at once.
27#[macro_export]
28macro_rules! to_va_list {
29    ($func:expr, $($args:expr),*) => {{
30        #[inline(always)]
31        unsafe fn should_be_in_unsafe_block() {}
32        should_be_in_unsafe_block();
33
34        unsafe extern "C" fn call_func(f: *mut libc::c_void, ap: $crate::va_list) {
35            let f: &Box<Fn($crate::va_list) + 'static> = std::mem::transmute(f);
36            f(ap);
37        }
38
39        let fu = $func;
40        let wrap = $crate::Wrap {
41            f: std::mem::transmute(call_func as usize),
42            c: $crate::convert_closure(fu),
43        };
44        $crate::create_va_list(Box::into_raw(Box::new(wrap)), $($args),*);
45    }};
46    ($func:expr) => {{
47        #[inline(always)]
48        unsafe fn should_be_in_unsafe_block() {}
49        should_be_in_unsafe_block();
50
51        unsafe extern "C" fn call_func(f: *mut libc::c_void, ap: $crate::va_list) {
52            let f: &Box<Fn($crate::va_list) + 'static> = std::mem::transmute(f);
53            f(ap);
54        }
55
56        let fu = $func;
57        let wrap = $crate::Wrap {
58            f: std::mem::transmute(call_func as usize),
59            c: $crate::convert_closure(fu),
60        };
61        $crate::create_va_list(Box::into_raw(Box::new(wrap)));
62    }}
63}
64
65
66#[repr(C)]
67#[doc(hidden)]
68pub struct Wrap {
69    pub f: extern "C" fn(*mut libc::c_void, va_list),
70    pub c: *mut libc::c_void,
71}
72
73extern "C" {
74    #[allow(improper_ctypes)]
75    #[doc(hidden)]
76    pub fn create_va_list(w: *mut Wrap, ...);
77}
78
79#[doc(hidden)]
80pub fn convert_closure<F: Fn(va_list) + 'static>(f: F) -> *mut libc::c_void {
81    let f: Box<Box<Fn(va_list) + 'static>> = Box::new(Box::new(f));
82    Box::into_raw(f) as *mut _
83}
84
85#[doc(hidden)]
86#[allow(non_camel_case_types)]
87pub enum _va_list {}
88
89#[allow(non_camel_case_types)]
90pub type va_list = *mut _va_list;