csbindgen/csbindgen-tests/src/lib.rs

421 lines
9.9 KiB
Rust
Raw Normal View History

2023-03-04 16:03:33 +00:00
use std::{
collections::HashSet,
2023-03-06 20:00:14 +00:00
ffi::{c_char, c_long, c_ulong, c_void, CString},
2023-03-04 16:03:33 +00:00
};
2023-02-28 05:49:04 +00:00
#[allow(dead_code)]
#[allow(non_snake_case)]
#[allow(non_camel_case_types)]
#[allow(non_upper_case_globals)]
mod lz4;
2023-02-26 18:31:44 +00:00
2023-02-27 23:08:46 +00:00
#[allow(dead_code)]
#[allow(non_snake_case)]
#[allow(non_camel_case_types)]
mod lz4_ffi;
2023-02-26 18:31:44 +00:00
// #[allow(dead_code)]
// #[allow(non_snake_case)]
// #[allow(non_camel_case_types)]
// #[allow(non_upper_case_globals)]
// mod bullet3;
// #[allow(dead_code)]
// #[allow(non_snake_case)]
// #[allow(non_camel_case_types)]
// mod bullet3_ffi;
// #[allow(dead_code)]
// #[allow(non_snake_case)]
// #[allow(non_camel_case_types)]
// #[allow(non_upper_case_globals)]
// mod quiche;
// #[allow(dead_code)]
// #[allow(non_snake_case)]
// #[allow(non_camel_case_types)]
// mod quiche_ffi;
// #[allow(dead_code)]
// #[allow(non_snake_case)]
// #[allow(non_camel_case_types)]
// #[allow(non_upper_case_globals)]
// mod zstd;
// #[allow(dead_code)]
// #[allow(non_snake_case)]
// #[allow(non_camel_case_types)]
// mod zstd_ffi;
2023-03-06 14:15:17 +00:00
#[allow(non_camel_case_types)]
pub type LONG_PTR = ::std::os::raw::c_longlong;
#[allow(non_camel_case_types)]
pub type PSSIZE_T = *mut LONG_PTR;
#[no_mangle]
pub extern "C" fn alias_test1(_a: PSSIZE_T) {}
#[no_mangle]
pub extern "C" fn alias_test2(_b: LONG_PTR) {}
#[no_mangle]
pub unsafe extern "C" fn nullpointer_test(p: *const u8) {
let ptr = unsafe { p.as_ref() };
match ptr {
Some(p2) => print!("pointer address: {}", *p2),
None => println!("null pointer!"),
};
}
2023-03-05 06:30:41 +00:00
#[no_mangle]
pub extern "C" fn callback_test(cb: extern "C" fn(a: i32) -> i32) -> i32 {
cb(100)
}
2023-03-06 20:00:14 +00:00
#[no_mangle]
pub extern "C" fn csharp_to_rust(cb: extern "C" fn(x: i32, y: i32) -> i32) {
let sum = cb(10, 20); // invoke C# method
println!("{sum}");
}
#[no_mangle]
pub extern "C" fn rust_to_csharp() -> extern fn(x: i32, y: i32) -> i32 {
sum // return rust method
}
extern "C" fn sum(x:i32, y:i32) -> i32 {
x + y
}
#[no_mangle]
pub extern "C" fn cbt(_cb: CallbackTable) {}
2023-03-05 06:30:41 +00:00
#[no_mangle]
pub extern "C" fn nullable_callback_test(cb: Option<extern "C" fn(a: i32) -> i32>) -> i32 {
match cb {
Some(f) => f(100),
None => -1,
}
}
2023-03-06 20:00:14 +00:00
#[no_mangle]
pub extern "C" fn types_iroiro(_i: isize, _u: usize, _cl: c_long, _cul: c_ulong) {}
2023-03-05 06:30:41 +00:00
#[no_mangle]
pub extern "C" fn callback_test2() -> extern "C" fn(a: i32) -> i32 {
callback
}
extern "C" fn callback(a: i32) -> i32 {
a * a
}
2023-03-05 08:18:52 +00:00
#[no_mangle]
2023-03-06 14:15:17 +00:00
pub extern "C" fn enum_test(i: IntEnumTest) -> i32 {
2023-03-05 08:18:52 +00:00
i as i32
}
2023-03-06 20:00:14 +00:00
#[repr(i8)]
2023-03-05 08:18:52 +00:00
pub enum IntEnumTest {
A = 1,
B = 2,
C = 10,
}
#[no_mangle]
#[allow(improper_ctypes_definitions)]
pub extern "C" fn ignore_nop() -> (i32, i32) {
println!("hello ignore!");
(1, 2)
}
#[no_mangle]
pub extern "C" fn nop() -> () {
println!("hello nop!");
}
2023-02-28 05:49:04 +00:00
#[no_mangle]
pub extern "C" fn my_add(x: i32, y: i32) -> i32 {
x + y
}
2023-03-04 16:03:33 +00:00
#[no_mangle]
pub extern "C" fn create_counter_context() -> *mut c_void {
let ctx = Box::new(CounterContext {
set: HashSet::new(),
});
Box::into_raw(ctx) as *mut c_void
}
#[no_mangle]
pub unsafe extern "C" fn insert_counter_context(context: *mut c_void, value: i32) {
let mut counter = Box::from_raw(context as *mut CounterContext);
counter.set.insert(value);
Box::into_raw(counter);
}
#[no_mangle]
pub unsafe extern "C" fn delete_counter_context(context: *mut c_void) {
let counter = Box::from_raw(context as *mut CounterContext);
for value in counter.set.iter() {
println!("counter value: {}", value)
}
}
2023-03-06 20:00:14 +00:00
#[no_mangle]
pub extern "C" fn pass_vector3(v3: MyVector3) {
println!("{}, {}, {}", v3.x, v3.y, v3.z);
}
#[no_mangle]
pub extern "C" fn return_union() -> MyUnion {
MyUnion { bar: 53 }
}
#[repr(C)]
pub union MyUnion {
pub foo: i32,
pub bar: i64,
}
#[repr(C)]
pub struct MyVector3 {
pub x: f32,
pub y: f32,
pub z: f32,
}
2023-03-04 16:03:33 +00:00
#[repr(C)]
pub struct CounterContext {
pub set: HashSet<i32>,
}
#[no_mangle]
2023-03-04 05:39:45 +00:00
pub extern "C" fn my_bool(
x: bool,
y: bool,
z: bool,
xr: *mut bool,
yr: *mut bool,
zr: *mut bool,
) -> bool {
unsafe {
*xr = x;
*yr = y;
*zr = z;
}
2023-03-04 05:39:45 +00:00
true
}
#[no_mangle]
pub extern "C" fn alloc_c_string() -> *mut c_char {
let str = CString::new("foo bar baz").unwrap();
str.into_raw()
}
2023-03-04 05:39:45 +00:00
#[no_mangle]
2023-03-06 20:00:14 +00:00
pub unsafe extern "C" fn free_c_string(str: *mut c_char) {
unsafe { CString::from_raw(str) };
2023-03-04 05:39:45 +00:00
}
#[no_mangle]
pub extern "C" fn alloc_u8_string() -> *mut ByteBuffer {
let str = format!("foo bar baz");
let buf = ByteBuffer::from_vec(str.into_bytes());
Box::into_raw(Box::new(buf))
2023-03-04 05:39:45 +00:00
}
#[no_mangle]
pub unsafe extern "C" fn free_u8_string(buffer: *mut ByteBuffer) {
let buf = Box::from_raw(buffer);
// drop inner buffer, if you need String, use String::from_utf8_unchecked(buf.destroy_into_vec()) instead.
buf.destroy();
}
#[no_mangle]
pub extern "C" fn alloc_u8_buffer() -> *mut ByteBuffer {
let vec: Vec<u8> = vec![1, 10, 100];
let buf = ByteBuffer::from_vec(vec);
Box::into_raw(Box::new(buf))
}
#[no_mangle]
pub unsafe extern "C" fn free_u8_buffer(buffer: *mut ByteBuffer) {
let buf = Box::from_raw(buffer);
// drop inner buffer, if you need Vec<u8>, use buf.destroy_into_vec() instead.
buf.destroy();
}
#[no_mangle]
pub extern "C" fn alloc_i32_buffer() -> *mut ByteBuffer {
let vec: Vec<i32> = vec![1, 10, 100, 1000, 10000];
let buf = ByteBuffer::from_vec_struct(vec);
Box::into_raw(Box::new(buf))
}
#[no_mangle]
pub unsafe extern "C" fn free_i32_buffer(buffer: *mut ByteBuffer) {
let buf = Box::from_raw(buffer);
// drop inner buffer, if you need Vec<i32>, use buf.destroy_into_vec_struct::<i32>() instead.
buf.destroy();
}
2023-03-04 05:54:48 +00:00
#[no_mangle]
pub extern "C" fn create_context() -> *mut Context {
let ctx = Box::new(Context { foo: true });
Box::into_raw(ctx)
}
#[no_mangle]
pub extern "C" fn delete_context(context: *mut Context) {
unsafe { Box::from_raw(context) };
}
#[no_mangle]
pub extern "C" fn call_bindgen() {
let path = std::env::current_dir().unwrap();
println!("starting dir: {}", path.display()); // csbindgen/csbindgen-tests
csbindgen::Builder::default()
.input_extern_file("../../../../csbindgen-tests/src/lib.rs")
.csharp_class_name("LibRust")
.csharp_dll_name("csbindgen_tests")
.generate_csharp_file("../../../../dotnet-sandbox/method_call.cs")
.unwrap();
}
2023-03-06 09:06:52 +00:00
#[no_mangle]
pub extern "C" fn call_bindgen_lz4() {
let path = std::env::current_dir().unwrap();
println!("starting dir: {}", path.display()); // csbindgen/csbindgen-tests
csbindgen::Builder::default()
2023-03-06 14:15:17 +00:00
.input_bindgen_file("../../../../csbindgen-tests/src/lz4.rs")
.method_filter(|x| x.starts_with("LZ4"))
.rust_method_prefix("csbindgen_")
.rust_file_header("use super::lz4;")
.rust_method_type_path("lz4")
2023-03-06 09:06:52 +00:00
.csharp_class_name("LibLz4")
.csharp_dll_name("csbindgen_tests")
2023-03-06 14:15:17 +00:00
.generate_to_file(
"../../../../csbindgen-tests/src/lz4_ffi.cs",
"../../../../dotnet-sandbox/lz4_bindgen.cs",
)
2023-03-06 09:06:52 +00:00
.unwrap();
}
2023-03-04 05:54:48 +00:00
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Context {
pub foo: bool,
}
2023-02-27 22:18:10 +00:00
#[test]
fn build_test() {
let path = std::env::current_dir().unwrap();
println!("starting dir: {}", path.display()); // csbindgen/csbindgen-tests
2023-02-26 18:31:44 +00:00
2023-02-28 05:49:04 +00:00
// // unsafe {
// // let num = lz4::LZ4_versionNumber();
// // println!("lz4 num: {}", num);
// // }
2023-02-26 18:31:44 +00:00
csbindgen::Builder::default()
.input_extern_file("csbindgen-tests/src/lib.rs")
.csharp_class_name("LibRust")
.csharp_dll_name("csbindgen_tests")
.generate_csharp_file("dotnet-sandbox/method_call.cs")
.unwrap();
}
#[repr(C)]
pub struct ByteBuffer {
ptr: *mut u8,
length: i32,
capacity: i32,
}
impl ByteBuffer {
pub fn len(&self) -> usize {
self.length
.try_into()
.expect("buffer length negative or overflowed")
}
pub fn from_vec(bytes: Vec<u8>) -> Self {
let length = i32::try_from(bytes.len()).expect("buffer length cannot fit into a i32.");
let capacity =
i32::try_from(bytes.capacity()).expect("buffer capacity cannot fit into a i32.");
// keep memory until call delete
let mut v = std::mem::ManuallyDrop::new(bytes);
Self {
ptr: v.as_mut_ptr(),
length,
capacity,
}
}
pub fn from_vec_struct<T: Sized>(bytes: Vec<T>) -> Self {
let element_size = std::mem::size_of::<T>() as i32;
let length = (bytes.len() as i32) * element_size;
let capacity = (bytes.capacity() as i32) * element_size;
let mut v = std::mem::ManuallyDrop::new(bytes);
Self {
ptr: v.as_mut_ptr() as *mut u8,
length,
capacity,
}
}
pub fn destroy_into_vec(self) -> Vec<u8> {
if self.ptr.is_null() {
vec![]
} else {
let capacity: usize = self
.capacity
.try_into()
.expect("buffer capacity negative or overflowed");
let length: usize = self
.length
.try_into()
.expect("buffer length negative or overflowed");
unsafe { Vec::from_raw_parts(self.ptr, length, capacity) }
}
}
pub fn destroy_into_vec_struct<T: Sized>(self) -> Vec<T> {
if self.ptr.is_null() {
vec![]
} else {
let element_size = std::mem::size_of::<T>() as i32;
let length = (self.length * element_size) as usize;
let capacity = (self.capacity * element_size) as usize;
unsafe { Vec::from_raw_parts(self.ptr as *mut T, length, capacity) }
}
}
pub fn destroy(self) {
drop(self.destroy_into_vec());
}
2023-02-26 18:31:44 +00:00
}
2023-03-06 09:06:52 +00:00
2023-03-06 20:00:14 +00:00
#[repr(C)]
pub struct CallbackTable {
pub foo: extern "C" fn(),
pub foobar: extern "C" fn(i: i32) -> i32,
}