use libc::{c_char, c_double, c_int, c_long, c_longlong};
use std::ffi::VaList;
-use std::slice;
-use std::ffi::CStr;
+use std::ffi::{CString, CStr};
-#[repr(C)]
-#[derive(Clone, Copy, Debug)]
-pub enum AnswerType {
- Double,
- Long,
- LongLong,
- Int,
- Byte,
- CStr,
- Skip,
+macro_rules! continue_if {
+ ($cond:expr) => {
+ if !($cond) {
+ return 0xff;
+ }
+ }
}
-#[repr(C)]
-pub union AnswerData {
- pub double: c_double,
- pub long: c_long,
- pub longlong: c_longlong,
- pub int: c_int,
- pub byte: c_char,
- pub cstr: *const c_char,
- pub skip_ty: AnswerType,
+unsafe fn compare_c_str(ptr: *const c_char, val: &str) -> bool {
+ let cstr0 = CStr::from_ptr(ptr);
+ let cstr1 = CString::new(val).unwrap();
+ &*cstr1 == cstr0
}
-#[repr(C)]
-pub struct Answer {
- tag: AnswerType,
- data: AnswerData,
+#[no_mangle]
+pub unsafe extern "C" fn check_list_0(mut ap: VaList) -> usize {
+ continue_if!(ap.arg::<c_longlong>() == 1);
+ continue_if!(ap.arg::<c_int>() == 2);
+ continue_if!(ap.arg::<c_longlong>() == 3);
+ 0
}
#[no_mangle]
-pub unsafe fn compare_answers(answers: &[Answer], mut ap: VaList) -> usize {
- for (i, answer) in answers.iter().enumerate() {
- match answer {
- Answer { tag: AnswerType::Double, data: AnswerData { double: d } } => {
- let tmp = ap.arg::<c_double>();
- if d.floor() != tmp.floor() {
- println!("Double: {} != {}", d, tmp);
- return i + 1;
- }
- }
- Answer { tag: AnswerType::Long, data: AnswerData { long: l } } => {
- let tmp = ap.arg::<c_long>();
- if *l != tmp {
- println!("Long: {} != {}", l, tmp);
- return i + 1;
- }
- }
- Answer { tag: AnswerType::LongLong, data: AnswerData { longlong: l } } => {
- let tmp = ap.arg::<c_longlong>();
- if *l != tmp {
- println!("Long Long: {} != {}", l, tmp);
- return i + 1;
- }
- }
- Answer { tag: AnswerType::Int, data: AnswerData { int: n } } => {
- let tmp = ap.arg::<c_int>();
- if *n != tmp {
- println!("Int: {} != {}", n, tmp);
- return i + 1;
- }
- }
- Answer { tag: AnswerType::Byte, data: AnswerData { byte: b } } => {
- let tmp = ap.arg::<c_char>();
- if *b != tmp {
- println!("Byte: {} != {}", b, tmp);
- return i + 1;
- }
- }
- Answer { tag: AnswerType::CStr, data: AnswerData { cstr: c0 } } => {
- let c1 = ap.arg::<*const c_char>();
- let cstr0 = CStr::from_ptr(*c0);
- let cstr1 = CStr::from_ptr(c1);
- if cstr0 != cstr1 {
- println!("C String: {:?} != {:?}", cstr0, cstr1);
- return i + 1;
- }
- }
- _ => {
- println!("Unknown type!");
- return i + 1;
- }
- }
- }
- return 0;
+pub unsafe extern "C" fn check_list_1(mut ap: VaList) -> usize {
+ continue_if!(ap.arg::<c_int>() == -1);
+ continue_if!(ap.arg::<c_char>() == 'A' as c_char);
+ continue_if!(ap.arg::<c_char>() == '4' as c_char);
+ continue_if!(ap.arg::<c_char>() == ';' as c_char);
+ continue_if!(ap.arg::<c_int>() == 0x32);
+ continue_if!(ap.arg::<c_int>() == 0x10000001);
+ continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Valid!"));
+ 0
}
#[no_mangle]
-pub unsafe extern "C" fn check_rust(argc: usize, answers: *const Answer, ap: VaList) -> usize {
- let slice = slice::from_raw_parts(answers, argc);
- compare_answers(slice, ap)
+pub unsafe extern "C" fn check_list_2(mut ap: VaList) -> usize {
+ continue_if!(ap.arg::<c_double>().floor() == 3.14f64.floor());
+ continue_if!(ap.arg::<c_long>() == 12);
+ continue_if!(ap.arg::<c_char>() == 'a' as c_char);
+ 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"));
+ 0
}
#[no_mangle]
-pub unsafe extern "C" fn check_rust_copy(argc: usize, answers: *const Answer,
- mut ap: VaList) -> usize {
- let slice = slice::from_raw_parts(answers, argc);
- let mut skip_n = 0;
- for (i, answer) in slice.iter().enumerate() {
- match answer {
- Answer { tag: AnswerType::Skip, data: AnswerData { skip_ty } } => {
- match skip_ty {
- AnswerType::Double => { ap.arg::<c_double>(); }
- AnswerType::Long => { ap.arg::<c_long>(); }
- AnswerType::LongLong => { ap.arg::<c_longlong>(); }
- AnswerType::Int => { ap.arg::<c_int>(); }
- AnswerType::Byte => { ap.arg::<c_char>(); }
- AnswerType::CStr => { ap.arg::<*const c_char>(); }
- _ => { return i; }
- };
- }
- _ => {
- skip_n = i;
- break;
- }
+pub unsafe extern "C" fn check_list_copy_0(mut ap: VaList) -> usize {
+ continue_if!(ap.arg::<c_double>().floor() == 6.28f64.floor());
+ continue_if!(ap.arg::<c_int>() == 16);
+ continue_if!(ap.arg::<c_char>() == 'A' as c_char);
+ continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Skip Me!"));
+ ap.copy(|mut ap| {
+ if compare_c_str(ap.arg::<*const c_char>(), "Correct") {
+ 0
+ } else {
+ 0xff
}
- }
-
- ap.copy(|ap| {
- compare_answers(&slice[skip_n..], ap)
})
}
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
+#include <stdio.h>
-typedef enum {
- TAG_DOUBLE,
- TAG_LONG,
- TAG_LONGLONG,
- TAG_INT,
- TAG_BYTE,
- TAG_CSTR,
- TAG_SKIP,
-} tag;
+extern size_t check_list_0(va_list ap);
+extern size_t check_list_1(va_list ap);
+extern size_t check_list_2(va_list ap);
+extern size_t check_list_copy_0(va_list ap);
-typedef struct {
- tag answer_type;
- union {
- double double_precision;
- long num_long;
- long long num_longlong;
- int num_int;
- int8_t byte;
- char* cstr;
- tag skip_ty;
- } answer_data;
-} answer;
-
-#define MK_DOUBLE(n) \
- { TAG_DOUBLE, { .double_precision = n } }
-#define MK_LONG(n) \
- { TAG_LONG, { .num_long = n } }
-#define MK_LONGLONG(n) \
- { TAG_LONGLONG, { .num_longlong = n } }
-#define MK_INT(n) \
- { TAG_INT, { .num_int = n } }
-#define MK_BYTE(b) \
- { TAG_BYTE, { .byte = b } }
-#define MK_CSTR(s) \
- { TAG_CSTR, { .cstr = s } }
-#define MK_SKIP(ty) \
- { TAG_SKIP, { .skip_ty = TAG_ ## ty } }
-
-extern size_t check_rust(size_t argc, const answer* answers, va_list ap);
-extern size_t check_rust_copy(size_t argc, const answer* answers, va_list ap);
-
-size_t test_check_rust(size_t argc, const answer* answers, ...) {
- size_t ret = 0;
- va_list ap;
- va_start(ap, answers);
- ret = check_rust(argc, answers, ap);
- va_end(ap);
- return ret;
-}
-
-size_t test_check_rust_copy(size_t argc, const answer* answers, ...) {
+int test_rust(size_t (*fn)(va_list), ...) {
size_t ret = 0;
va_list ap;
- va_start(ap, answers);
- ret = check_rust_copy(argc, answers, ap);
+ va_start(ap, fn);
+ ret = fn(ap);
va_end(ap);
return ret;
}
int main(int argc, char* argv[]) {
- answer test_alignment0[] = {MK_LONGLONG(0x01LL), MK_INT(0x02), MK_LONGLONG(0x03LL)};
- assert(test_check_rust(3, test_alignment0, 0x01LL, 0x02, 0x03LL) == 0);
+ assert(test_rust(check_list_0, 0x01LL, 0x02, 0x03LL) == 0);
- answer test_alignment1[] = {MK_INT(-1), MK_BYTE('A'), MK_BYTE('4'), MK_BYTE(';'),
- MK_INT(0x32), MK_INT(0x10000001), MK_CSTR("Valid!")};
- assert(test_check_rust(7, test_alignment1, -1, 'A', '4', ';', 0x32, 0x10000001,
- "Valid!") == 0);
+ assert(test_rust(check_list_1, -1, 'A', '4', ';', 0x32, 0x10000001, "Valid!") == 0);
- answer basic_answers[] = {MK_DOUBLE(3.14), MK_LONG(12l), MK_BYTE('a'),
- MK_DOUBLE(6.28), MK_CSTR("Hello"), MK_INT(42),
- MK_CSTR("World")};
- assert(test_check_rust(7, basic_answers, 3.14, 12l, 'a', 6.28, "Hello",
- 42, "World") == 0);
+ assert(test_rust(check_list_2, 3.14, 12l, 'a', 6.28, "Hello", 42, "World") == 0);
- answer copy_answers[] = { MK_SKIP(DOUBLE), MK_SKIP(INT), MK_SKIP(BYTE), MK_SKIP(CSTR),
- MK_CSTR("Correctly skipped and copied list") };
- assert(test_check_rust_copy(5, copy_answers, 6.28, 16, 'A', "Skip Me!",
- "Correctly skipped and copied list") == 0);
+ assert(test_rust(check_list_copy_0, 6.28, 16, 'A', "Skip Me!", "Correct") == 0);
return 0;
}