// Copyright 2018 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #![crate_type = "staticlib"] #![feature(c_variadic)] #![feature(libc)] extern crate libc; use libc::{c_char, c_double, c_int, c_long, c_longlong}; use std::ffi::VaList; use std::slice; use std::ffi::CStr; #[repr(C)] #[derive(Clone, Copy, Debug)] pub enum AnswerType { Double, Long, LongLong, Int, Byte, CStr, Skip, } #[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, } #[repr(C)] pub struct Answer { tag: AnswerType, data: AnswerData, } #[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::(); if d.floor() != tmp.floor() { println!("Double: {} != {}", d, tmp); return i + 1; } } Answer { tag: AnswerType::Long, data: AnswerData { long: l } } => { let tmp = ap.arg::(); if *l != tmp { println!("Long: {} != {}", l, tmp); return i + 1; } } Answer { tag: AnswerType::LongLong, data: AnswerData { longlong: l } } => { let tmp = ap.arg::(); if *l != tmp { println!("Long Long: {} != {}", l, tmp); return i + 1; } } Answer { tag: AnswerType::Int, data: AnswerData { int: n } } => { let tmp = ap.arg::(); if *n != tmp { println!("Int: {} != {}", n, tmp); return i + 1; } } Answer { tag: AnswerType::Byte, data: AnswerData { byte: b } } => { let tmp = ap.arg::(); 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; } #[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) } #[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::(); } AnswerType::Long => { ap.arg::(); } AnswerType::LongLong => { ap.arg::(); } AnswerType::Int => { ap.arg::(); } AnswerType::Byte => { ap.arg::(); } AnswerType::CStr => { ap.arg::<*const c_char>(); } _ => { return i; } }; } _ => { skip_n = i; break; } } } ap.copy(|ap| { compare_answers(&slice[skip_n..], ap) }) }