115 lines
2.7 KiB
Rust
115 lines
2.7 KiB
Rust
#![feature(c_variadic)]
|
|
|
|
use std::ffi::{CStr, VaList, c_char, c_double, c_int, c_long};
|
|
|
|
fn ignores_arguments() {
|
|
unsafe extern "C" fn variadic(_: ...) {}
|
|
|
|
unsafe { variadic() };
|
|
unsafe { variadic(1, 2, 3) };
|
|
}
|
|
|
|
fn echo() {
|
|
unsafe extern "C" fn variadic(mut ap: ...) -> i32 {
|
|
ap.arg()
|
|
}
|
|
|
|
assert_eq!(unsafe { variadic(1) }, 1);
|
|
assert_eq!(unsafe { variadic(3, 2, 1) }, 3);
|
|
}
|
|
|
|
fn forward_by_val() {
|
|
unsafe fn helper(mut ap: VaList) -> i32 {
|
|
ap.arg()
|
|
}
|
|
|
|
unsafe extern "C" fn variadic(ap: ...) -> i32 {
|
|
helper(ap)
|
|
}
|
|
|
|
assert_eq!(unsafe { variadic(1) }, 1);
|
|
assert_eq!(unsafe { variadic(3, 2, 1) }, 3);
|
|
}
|
|
|
|
fn forward_by_ref() {
|
|
unsafe fn helper(ap: &mut VaList) -> i32 {
|
|
ap.arg()
|
|
}
|
|
|
|
unsafe extern "C" fn variadic(mut ap: ...) -> i32 {
|
|
helper(&mut ap)
|
|
}
|
|
|
|
assert_eq!(unsafe { variadic(1) }, 1);
|
|
assert_eq!(unsafe { variadic(3, 2, 1) }, 3);
|
|
}
|
|
|
|
#[allow(improper_ctypes_definitions)]
|
|
fn nested() {
|
|
unsafe fn helper(mut ap1: VaList, mut ap2: VaList) -> (i32, i32) {
|
|
(ap1.arg(), ap2.arg())
|
|
}
|
|
|
|
unsafe extern "C" fn variadic2(ap1: VaList, ap2: ...) -> (i32, i32) {
|
|
helper(ap1, ap2)
|
|
}
|
|
|
|
unsafe extern "C" fn variadic1(ap1: ...) -> (i32, i32) {
|
|
variadic2(ap1, 2, 2)
|
|
}
|
|
|
|
assert_eq!(unsafe { variadic1(1) }, (1, 2));
|
|
|
|
let (a, b) = unsafe { variadic1(1, 1) };
|
|
|
|
assert_eq!(a, 1);
|
|
assert_eq!(b, 2);
|
|
}
|
|
|
|
fn various_types() {
|
|
unsafe extern "C" fn check_list_2(mut ap: ...) {
|
|
macro_rules! continue_if {
|
|
($cond:expr) => {
|
|
if !($cond) {
|
|
panic!();
|
|
}
|
|
};
|
|
}
|
|
|
|
unsafe fn compare_c_str(ptr: *const c_char, val: &str) -> bool {
|
|
match CStr::from_ptr(ptr).to_str() {
|
|
Ok(cstr) => cstr == val,
|
|
Err(_) => panic!(),
|
|
}
|
|
}
|
|
|
|
continue_if!(ap.arg::<c_double>().floor() == 3.14f64.floor());
|
|
continue_if!(ap.arg::<c_long>() == 12);
|
|
continue_if!(ap.arg::<c_int>() == 'a' as c_int);
|
|
continue_if!(ap.arg::<c_double>().floor() == 6.18f64.floor());
|
|
continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Hello"));
|
|
continue_if!(ap.arg::<c_int>() == 42);
|
|
continue_if!(compare_c_str(ap.arg::<*const c_char>(), "World"));
|
|
}
|
|
|
|
unsafe {
|
|
check_list_2(
|
|
3.14 as c_double,
|
|
12 as c_long,
|
|
b'a' as c_int,
|
|
6.28 as c_double,
|
|
c"Hello".as_ptr(),
|
|
42 as c_int,
|
|
c"World".as_ptr(),
|
|
);
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
ignores_arguments();
|
|
echo();
|
|
forward_by_val();
|
|
forward_by_ref();
|
|
nested();
|
|
various_types();
|
|
}
|