diff --git a/.gitmodules b/.gitmodules index 6cd1abf41..a694cec89 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "crates/mun_abi/c"] path = crates/mun_abi/c url = ../../mun-lang/abi-c +[submodule "crates/mun_runtime_capi/c"] + path = crates/mun_runtime_capi/c + url = ../../mun-lang/runtime-c.git diff --git a/crates/mun_abi/build.rs b/crates/mun_abi/build.rs index 7939d166c..f002e1c7f 100644 --- a/crates/mun_abi/build.rs +++ b/crates/mun_abi/build.rs @@ -35,12 +35,14 @@ fn main() { .whitelist_type("Mun.*") .blacklist_type("MunPrivacy.*") .parse_callbacks(Box::new(RemoveVendorName)) + .raw_line("#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]") + .raw_line("use crate::Privacy;") .generate() .expect("Unable to generate bindings for 'mun_abi.h'"); - let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + let out_path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); bindings - .write_to_file(out_path.join("bindings.rs")) + .write_to_file(out_path.join("src/autogen.rs")) .expect(&format!( "Couldn't write bindings to '{}'", out_path.as_path().to_string_lossy() diff --git a/crates/mun_abi/src/autogen.rs b/crates/mun_abi/src/autogen.rs index d5b3dc207..7e780a1d2 100644 --- a/crates/mun_abi/src/autogen.rs +++ b/crates/mun_abi/src/autogen.rs @@ -1,563 +1,342 @@ -#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] - -use crate::prelude::*; +/* automatically generated by rust-bindgen */ -include!(concat!(env!("OUT_DIR"), "/bindings.rs")); - -use std::ffi::{c_void, CStr}; -use std::slice; +#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] +use crate::Privacy; -impl TypeInfo { - /// Returns the type's name. - pub fn name(&self) -> &str { - unsafe { CStr::from_ptr(self.name) } - .to_str() - .expect("Type name contains invalid UTF8") - } +#[doc = "
"] +#[repr(C)] +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct Guid { + pub b: [u8; 16usize], } - -impl PartialEq for TypeInfo { - fn eq(&self, other: &Self) -> bool { - self.guid == other.guid - } +#[test] +fn bindgen_test_layout_Guid() { + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(Guid)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!("Alignment of ", stringify!(Guid)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).b as *const _ as usize }, + 0usize, + concat!("Offset of field: ", stringify!(Guid), "::", stringify!(b)) + ); } - -impl FunctionSignature { - /// Returns the function's name. - pub fn name(&self) -> &str { - unsafe { CStr::from_ptr(self.name) } - .to_str() - .expect("Function name contains invalid UTF8") - } - - /// Returns the function's privacy level. - pub fn privacy(&self) -> Privacy { - self.privacy - } - - /// Returns the function's arguments' types. - pub fn arg_types(&self) -> &[TypeInfo] { - if self.num_arg_types == 0 { - &[] - } else { - unsafe { slice::from_raw_parts(self.arg_types, self.num_arg_types as usize) } - } - } - - /// Returns the function's return type - pub fn return_type(&self) -> Option<&TypeInfo> { - unsafe { self.return_type.as_ref() } - } +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct TypeInfo { + pub guid: Guid, + pub name: *const ::std::os::raw::c_char, } - -impl ModuleInfo { - /// Returns the module's full path. - pub fn path(&self) -> &str { - unsafe { CStr::from_ptr(self.path) } - .to_str() - .expect("Module path contains invalid UTF8") - } - - // /// Finds the type's fields that match `filter`. - // pub fn find_fields(&self, filter: fn(&&FieldInfo) -> bool) -> impl Iterator { - // self.fields.iter().map(|f| *f).filter(filter) - // } - - // /// Retrieves the type's field with the specified `name`, if it exists. - // pub fn get_field(&self, name: &str) -> Option<&FieldInfo> { - // self.fields.iter().find(|f| f.name == name).map(|f| *f) - // } - - // /// Retrieves the type's fields. - // pub fn get_fields(&self) -> impl Iterator { - // self.fields.iter().map(|f| *f) - // } - - /// Returns the module's functions. - pub fn functions(&self) -> &[FunctionInfo] { - if self.num_functions == 0 { - &[] - } else { - unsafe { slice::from_raw_parts(self.functions, self.num_functions as usize) } - } - } +#[test] +fn bindgen_test_layout_TypeInfo() { + assert_eq!( + ::std::mem::size_of::(), + 24usize, + concat!("Size of: ", stringify!(TypeInfo)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(TypeInfo)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).guid as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(TypeInfo), + "::", + stringify!(guid) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).name as *const _ as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(TypeInfo), + "::", + stringify!(name) + ) + ); } - -impl DispatchTable { - /// Returns an iterator over pairs of mutable function pointers and signatures. - pub fn iter_mut(&mut self) -> impl Iterator { - if self.num_entries == 0 { - (&mut []).iter_mut().zip((&[]).iter()) - } else { - let ptrs = - unsafe { slice::from_raw_parts_mut(self.fn_ptrs, self.num_entries as usize) }; - let signatures = - unsafe { slice::from_raw_parts(self.signatures, self.num_entries as usize) }; - - ptrs.iter_mut().zip(signatures.iter()) - } - } - - /// Returns mutable functions pointers. - pub fn ptrs_mut(&mut self) -> &mut [*const c_void] { - if self.num_entries == 0 { - &mut [] - } else { - unsafe { slice::from_raw_parts_mut(self.fn_ptrs, self.num_entries as usize) } - } - } - - /// Returns function signatures. - pub fn signatures(&self) -> &[FunctionSignature] { - if self.num_entries == 0 { - &[] - } else { - unsafe { slice::from_raw_parts(self.signatures, self.num_entries as usize) } - } - } - - /// Returns a function pointer, without doing bounds checking. - /// - /// This is generally not recommended, use with caution! Calling this method with an - /// out-of-bounds index is _undefined behavior_ even if the resulting reference is not used. - /// For a safe alternative see [get_ptr](#method.get_ptr). - pub unsafe fn get_ptr_unchecked(&self, idx: u32) -> *const c_void { - *self.fn_ptrs.offset(idx as isize) - } - - /// Returns a function pointer at the given index, or `None` if out of bounds. - pub fn get_ptr(&self, idx: u32) -> Option<*const c_void> { - if idx < self.num_entries { - Some(unsafe { self.get_ptr_unchecked(idx) }) - } else { - None - } - } - - /// Returns a mutable reference to a function pointer, without doing bounds checking. - /// - /// This is generally not recommended, use with caution! Calling this method with an - /// out-of-bounds index is _undefined behavior_ even if the resulting reference is not used. - /// For a safe alternative see [get_ptr_mut](#method.get_ptr_mut). - pub unsafe fn get_ptr_unchecked_mut(&self, idx: u32) -> &mut *const c_void { - &mut *self.fn_ptrs.offset(idx as isize) - } - - /// Returns a mutable reference to a function pointer at the given index, or `None` if out of - /// bounds. - pub fn get_ptr_mut(&self, idx: u32) -> Option<&mut *const c_void> { - if idx < self.num_entries { - Some(unsafe { self.get_ptr_unchecked_mut(idx) }) - } else { - None - } - } +#[doc = "
"] +#[repr(C)] +#[derive(Clone)] +pub struct FunctionSignature { + pub name: *const ::std::os::raw::c_char, + pub arg_types: *const TypeInfo, + pub return_type: *const TypeInfo, + pub num_arg_types: u16, + pub privacy: Privacy, } - -impl AssemblyInfo { - /// Returns an iterator over the assembly's dependencies. - pub fn dependencies(&self) -> impl Iterator { - let dependencies = if self.num_dependencies == 0 { - &[] - } else { - unsafe { slice::from_raw_parts(self.dependencies, self.num_dependencies as usize) } - }; - - dependencies.iter().map(|d| { - unsafe { CStr::from_ptr(*d) } - .to_str() - .expect("dependency path contains invalid UTF8") - }) - } +#[test] +fn bindgen_test_layout_FunctionSignature() { + assert_eq!( + ::std::mem::size_of::(), + 32usize, + concat!("Size of: ", stringify!(FunctionSignature)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(FunctionSignature)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).name as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(FunctionSignature), + "::", + stringify!(name) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).arg_types as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(FunctionSignature), + "::", + stringify!(arg_types) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).return_type as *const _ as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(FunctionSignature), + "::", + stringify!(return_type) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).num_arg_types as *const _ as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(FunctionSignature), + "::", + stringify!(num_arg_types) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).privacy as *const _ as usize }, + 26usize, + concat!( + "Offset of field: ", + stringify!(FunctionSignature), + "::", + stringify!(privacy) + ) + ); } - -#[cfg(test)] -mod tests { - use super::*; - use std::ffi::CString; - use std::os::raw::c_char; - use std::ptr; - - fn fake_type_info(name: &CStr) -> TypeInfo { - TypeInfo { - guid: FAKE_TYPE_GUID, - name: name.as_ptr(), - } - } - - const FAKE_TYPE_GUID: Guid = Guid { - b: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], - }; - - const FAKE_TYPE_NAME: &'static str = "type-name"; - - #[test] - fn test_type_info_name() { - let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name."); - let type_info = fake_type_info(&type_name); - - assert_eq!(type_info.name(), FAKE_TYPE_NAME); - } - - #[test] - fn test_type_info_eq() { - let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name."); - let type_info = fake_type_info(&type_name); - - assert_eq!(type_info, type_info); - } - - fn fake_fn_signature( - name: &CStr, - arg_types: &[TypeInfo], - return_type: Option<&TypeInfo>, - privacy: Privacy, - ) -> FunctionSignature { - FunctionSignature { - name: name.as_ptr(), - arg_types: arg_types.as_ptr(), - return_type: return_type.map_or(ptr::null(), |t| t as *const TypeInfo), - num_arg_types: arg_types.len() as u16, - privacy, - } - } - - const FAKE_FN_NAME: &'static str = "fn-name"; - - #[test] - fn test_fn_signature_name() { - let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); - let fn_signature = fake_fn_signature(&fn_name, &[], None, Privacy::Public); - - assert_eq!(fn_signature.name(), FAKE_FN_NAME); - } - - #[test] - fn test_fn_signature_privacy() { - let privacy = Privacy::Private; - let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); - let fn_signature = fake_fn_signature(&fn_name, &[], None, privacy); - - assert_eq!(fn_signature.privacy(), privacy); - } - - #[test] - fn test_fn_signature_arg_types_none() { - let arg_types = &[]; - let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); - let fn_signature = fake_fn_signature(&fn_name, arg_types, None, Privacy::Public); - - assert_eq!(fn_signature.arg_types(), arg_types); - } - - #[test] - fn test_fn_signature_arg_types_some() { - let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name."); - let type_info = fake_type_info(&type_name); - - let arg_types = &[type_info]; - let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); - let fn_signature = fake_fn_signature(&fn_name, arg_types, None, Privacy::Public); - - assert_eq!(fn_signature.arg_types(), arg_types); - } - - #[test] - fn test_fn_signature_return_type_none() { - let return_type = None; - let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); - let fn_signature = fake_fn_signature(&fn_name, &[], return_type, Privacy::Public); - - assert_eq!(fn_signature.return_type(), return_type); - } - - #[test] - fn test_fn_signature_return_type_some() { - let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name."); - let type_info = fake_type_info(&type_name); - - let return_type = Some(&type_info); - let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); - let fn_signature = fake_fn_signature(&fn_name, &[], return_type, Privacy::Public); - - assert_eq!(fn_signature.return_type(), return_type); - } - - fn fake_module_info(path: &CStr, functions: &[FunctionInfo]) -> ModuleInfo { - ModuleInfo { - path: path.as_ptr(), - functions: functions.as_ptr(), - num_functions: functions.len() as u32, - } - } - - const FAKE_MODULE_PATH: &'static str = "path::to::module"; - - #[test] - fn test_module_info_path() { - let module_path = CString::new(FAKE_MODULE_PATH).expect("Invalid fake module path."); - let module = fake_module_info(&module_path, &[]); - - assert_eq!(module.path(), FAKE_MODULE_PATH); - } - - #[test] - fn test_module_info_functions_none() { - let functions = &[]; - let module_path = CString::new(FAKE_MODULE_PATH).expect("Invalid fake module path."); - let module = fake_module_info(&module_path, functions); - - assert_eq!(module.functions().len(), functions.len()); - } - - #[test] - fn test_module_info_functions_some() { - let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name."); - let type_info = fake_type_info(&type_name); - - let return_type = Some(&type_info); - let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); - let fn_signature = fake_fn_signature(&fn_name, &[], return_type, Privacy::Public); - - let fn_info = FunctionInfo { - signature: fn_signature, - fn_ptr: ptr::null(), - }; - - let functions = &[fn_info]; - let module_path = CString::new(FAKE_MODULE_PATH).expect("Invalid fake module path."); - let module = fake_module_info(&module_path, functions); - - let result = module.functions(); - assert_eq!(result.len(), functions.len()); - for (lhs, rhs) in result.iter().zip(functions.iter()) { - assert_eq!(lhs.fn_ptr, rhs.fn_ptr); - assert_eq!(lhs.signature.name(), rhs.signature.name()); - assert_eq!(lhs.signature.arg_types(), rhs.signature.arg_types()); - assert_eq!(lhs.signature.return_type(), rhs.signature.return_type()); - assert_eq!(lhs.signature.privacy(), rhs.signature.privacy()); - } - } - - fn fake_dispatch_table( - fn_signatures: &[FunctionSignature], - fn_ptrs: &mut [*const c_void], - ) -> DispatchTable { - assert!(fn_signatures.len() == fn_ptrs.len()); - - DispatchTable { - signatures: fn_signatures.as_ptr(), - fn_ptrs: fn_ptrs.as_mut_ptr(), - num_entries: fn_signatures.len() as u32, - } - } - - #[test] - fn test_dispatch_table_iter_mut_none() { - let signatures = &[]; - let fn_ptrs = &mut []; - let mut dispatch_table = fake_dispatch_table(signatures, fn_ptrs); - - let iter = fn_ptrs.iter_mut().zip(signatures.iter()); - assert_eq!(dispatch_table.iter_mut().count(), iter.count()); - } - - #[test] - fn test_dispatch_table_iter_mut_some() { - let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name."); - let type_info = fake_type_info(&type_name); - - let return_type = Some(&type_info); - let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); - let fn_signature = fake_fn_signature(&fn_name, &[], return_type, Privacy::Public); - - let signatures = &[fn_signature]; - let fn_ptrs = &mut [ptr::null()]; - let mut dispatch_table = fake_dispatch_table(signatures, fn_ptrs); - - let iter = fn_ptrs.iter_mut().zip(signatures.iter()); - assert_eq!(dispatch_table.iter_mut().count(), iter.len()); - - for (lhs, rhs) in dispatch_table.iter_mut().zip(iter) { - assert_eq!(lhs.0, rhs.0); - assert_eq!(lhs.1.name(), rhs.1.name()); - assert_eq!(lhs.1.arg_types(), rhs.1.arg_types()); - assert_eq!(lhs.1.return_type(), rhs.1.return_type()); - assert_eq!(lhs.1.privacy(), rhs.1.privacy()); - } - } - - #[test] - fn test_dispatch_table_ptrs_mut() { - let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name."); - let type_info = fake_type_info(&type_name); - - let return_type = Some(&type_info); - let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); - let fn_signature = fake_fn_signature(&fn_name, &[], return_type, Privacy::Public); - - let signatures = &[fn_signature]; - let fn_ptrs = &mut [ptr::null()]; - let mut dispatch_table = fake_dispatch_table(signatures, fn_ptrs); - - let result = dispatch_table.ptrs_mut(); - assert_eq!(result.len(), fn_ptrs.len()); - for (lhs, rhs) in result.iter().zip(fn_ptrs.iter()) { - assert_eq!(lhs, rhs); - } - } - - #[test] - fn test_dispatch_table_signatures() { - let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name."); - let type_info = fake_type_info(&type_name); - - let return_type = Some(&type_info); - let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); - let fn_signature = fake_fn_signature(&fn_name, &[], return_type, Privacy::Public); - - let signatures = &[fn_signature]; - let fn_ptrs = &mut [ptr::null()]; - let dispatch_table = fake_dispatch_table(signatures, fn_ptrs); - - let result = dispatch_table.signatures(); - assert_eq!(result.len(), signatures.len()); - for (lhs, rhs) in result.iter().zip(signatures.iter()) { - assert_eq!(lhs.name(), rhs.name()); - assert_eq!(lhs.arg_types(), rhs.arg_types()); - assert_eq!(lhs.return_type(), rhs.return_type()); - assert_eq!(lhs.privacy(), rhs.privacy()); - } - } - - #[test] - fn test_dispatch_table_get_ptr_unchecked() { - let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name."); - let type_info = fake_type_info(&type_name); - - let return_type = Some(&type_info); - let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); - let fn_signature = fake_fn_signature(&fn_name, &[], return_type, Privacy::Public); - - let signatures = &[fn_signature]; - let fn_ptrs = &mut [ptr::null()]; - - let dispatch_table = fake_dispatch_table(signatures, fn_ptrs); - assert_eq!(unsafe { dispatch_table.get_ptr_unchecked(0) }, fn_ptrs[0]); - } - - #[test] - fn test_dispatch_table_get_ptr_none() { - let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name."); - let type_info = fake_type_info(&type_name); - - let return_type = Some(&type_info); - let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); - let fn_signature = fake_fn_signature(&fn_name, &[], return_type, Privacy::Public); - - let signatures = &[fn_signature]; - let fn_ptrs = &mut [ptr::null()]; - - let dispatch_table = fake_dispatch_table(signatures, fn_ptrs); - assert_eq!(dispatch_table.get_ptr(1), None); - } - - #[test] - fn test_dispatch_table_get_ptr_some() { - let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name."); - let type_info = fake_type_info(&type_name); - - let return_type = Some(&type_info); - let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); - let fn_signature = fake_fn_signature(&fn_name, &[], return_type, Privacy::Public); - - let signatures = &[fn_signature]; - let fn_ptrs = &mut [ptr::null()]; - - let dispatch_table = fake_dispatch_table(signatures, fn_ptrs); - assert_eq!(dispatch_table.get_ptr(0), Some(fn_ptrs[0])); - } - - #[test] - fn test_dispatch_table_get_ptr_unchecked_mut() { - let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name."); - let type_info = fake_type_info(&type_name); - - let return_type = Some(&type_info); - let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); - let fn_signature = fake_fn_signature(&fn_name, &[], return_type, Privacy::Public); - - let signatures = &[fn_signature]; - let fn_ptrs = &mut [ptr::null()]; - - let dispatch_table = fake_dispatch_table(signatures, fn_ptrs); - assert_eq!( - unsafe { dispatch_table.get_ptr_unchecked_mut(0) }, - &mut fn_ptrs[0] - ); - } - - #[test] - fn test_dispatch_table_get_ptr_mut_none() { - let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name."); - let type_info = fake_type_info(&type_name); - - let return_type = Some(&type_info); - let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); - let fn_signature = fake_fn_signature(&fn_name, &[], return_type, Privacy::Public); - - let signatures = &[fn_signature]; - let fn_ptrs = &mut [ptr::null()]; - - let dispatch_table = fake_dispatch_table(signatures, fn_ptrs); - assert_eq!(dispatch_table.get_ptr_mut(1), None); - } - - #[test] - fn test_dispatch_table_get_ptr_mut_some() { - let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name."); - let type_info = fake_type_info(&type_name); - - let return_type = Some(&type_info); - let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); - let fn_signature = fake_fn_signature(&fn_name, &[], return_type, Privacy::Public); - - let signatures = &[fn_signature]; - let fn_ptrs = &mut [ptr::null()]; - - let dispatch_table = fake_dispatch_table(signatures, fn_ptrs); - assert_eq!(dispatch_table.get_ptr_mut(0), Some(&mut fn_ptrs[0])); - } - - fn fake_assembly_info( - symbols: ModuleInfo, - dispatch_table: DispatchTable, - dependencies: &[*const c_char], - ) -> AssemblyInfo { - AssemblyInfo { - symbols, - dispatch_table, - dependencies: dependencies.as_ptr(), - num_dependencies: dependencies.len() as u32, - } - } - - const FAKE_DEPENDENCY: &'static str = "path/to/dependency.dylib"; - - #[test] - fn test_assembly_info_dependencies() { - let module_path = CString::new(FAKE_MODULE_PATH).expect("Invalid fake module path."); - let module = fake_module_info(&module_path, &[]); - - let dispatch_table = fake_dispatch_table(&[], &mut []); - - let dependency = CString::new(FAKE_DEPENDENCY).expect("Invalid fake dependency."); - let dependencies = &[dependency.as_ptr()]; - let assembly = fake_assembly_info(module, dispatch_table, dependencies); - - assert_eq!(assembly.dependencies().count(), dependencies.len()); - for (lhs, rhs) in assembly.dependencies().zip([FAKE_DEPENDENCY].iter()) { - assert_eq!(lhs, *rhs) - } - } +#[doc = "
"] +#[repr(C)] +#[derive(Clone)] +pub struct FunctionInfo { + pub signature: FunctionSignature, + pub fn_ptr: *const ::std::os::raw::c_void, +} +#[test] +fn bindgen_test_layout_FunctionInfo() { + assert_eq!( + ::std::mem::size_of::(), + 40usize, + concat!("Size of: ", stringify!(FunctionInfo)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(FunctionInfo)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).signature as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(FunctionInfo), + "::", + stringify!(signature) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).fn_ptr as *const _ as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(FunctionInfo), + "::", + stringify!(fn_ptr) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ModuleInfo { + pub path: *const ::std::os::raw::c_char, + pub functions: *const FunctionInfo, + pub num_functions: u32, +} +#[test] +fn bindgen_test_layout_ModuleInfo() { + assert_eq!( + ::std::mem::size_of::(), + 24usize, + concat!("Size of: ", stringify!(ModuleInfo)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(ModuleInfo)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).path as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(ModuleInfo), + "::", + stringify!(path) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).functions as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(ModuleInfo), + "::", + stringify!(functions) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).num_functions as *const _ as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(ModuleInfo), + "::", + stringify!(num_functions) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DispatchTable { + pub signatures: *const FunctionSignature, + pub fn_ptrs: *mut *const ::std::os::raw::c_void, + pub num_entries: u32, +} +#[test] +fn bindgen_test_layout_DispatchTable() { + assert_eq!( + ::std::mem::size_of::(), + 24usize, + concat!("Size of: ", stringify!(DispatchTable)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(DispatchTable)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).signatures as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(DispatchTable), + "::", + stringify!(signatures) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).fn_ptrs as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(DispatchTable), + "::", + stringify!(fn_ptrs) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).num_entries as *const _ as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(DispatchTable), + "::", + stringify!(num_entries) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct AssemblyInfo { + pub symbols: ModuleInfo, + pub dispatch_table: DispatchTable, + pub dependencies: *const *const ::std::os::raw::c_char, + pub num_dependencies: u32, +} +#[test] +fn bindgen_test_layout_AssemblyInfo() { + assert_eq!( + ::std::mem::size_of::(), + 64usize, + concat!("Size of: ", stringify!(AssemblyInfo)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(AssemblyInfo)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).symbols as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(AssemblyInfo), + "::", + stringify!(symbols) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).dispatch_table as *const _ as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(AssemblyInfo), + "::", + stringify!(dispatch_table) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).dependencies as *const _ as usize }, + 48usize, + concat!( + "Offset of field: ", + stringify!(AssemblyInfo), + "::", + stringify!(dependencies) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).num_dependencies as *const _ as usize }, + 56usize, + concat!( + "Offset of field: ", + stringify!(AssemblyInfo), + "::", + stringify!(num_dependencies) + ) + ); } diff --git a/crates/mun_abi/src/autogen_impl.rs b/crates/mun_abi/src/autogen_impl.rs new file mode 100644 index 000000000..7d35de78d --- /dev/null +++ b/crates/mun_abi/src/autogen_impl.rs @@ -0,0 +1,575 @@ +use crate::prelude::*; + +use std::ffi::{c_void, CStr}; +use std::marker::{Send, Sync}; +use std::slice; + +impl TypeInfo { + /// Returns the type's name. + pub fn name(&self) -> &str { + unsafe { CStr::from_ptr(self.name) } + .to_str() + .expect("Type name contains invalid UTF8") + } +} + +impl PartialEq for TypeInfo { + fn eq(&self, other: &Self) -> bool { + self.guid == other.guid + } +} + +unsafe impl Send for TypeInfo {} +unsafe impl Sync for TypeInfo {} + +impl FunctionSignature { + /// Returns the function's name. + pub fn name(&self) -> &str { + unsafe { CStr::from_ptr(self.name) } + .to_str() + .expect("Function name contains invalid UTF8") + } + + /// Returns the function's privacy level. + pub fn privacy(&self) -> Privacy { + self.privacy + } + + /// Returns the function's arguments' types. + pub fn arg_types(&self) -> &[TypeInfo] { + if self.num_arg_types == 0 { + &[] + } else { + unsafe { slice::from_raw_parts(self.arg_types, self.num_arg_types as usize) } + } + } + + /// Returns the function's return type + pub fn return_type(&self) -> Option<&TypeInfo> { + unsafe { self.return_type.as_ref() } + } +} + +unsafe impl Send for FunctionSignature {} +unsafe impl Sync for FunctionSignature {} + +unsafe impl Send for FunctionInfo {} +unsafe impl Sync for FunctionInfo {} + +impl ModuleInfo { + /// Returns the module's full path. + pub fn path(&self) -> &str { + unsafe { CStr::from_ptr(self.path) } + .to_str() + .expect("Module path contains invalid UTF8") + } + + // /// Finds the type's fields that match `filter`. + // pub fn find_fields(&self, filter: fn(&&FieldInfo) -> bool) -> impl Iterator { + // self.fields.iter().map(|f| *f).filter(filter) + // } + + // /// Retrieves the type's field with the specified `name`, if it exists. + // pub fn get_field(&self, name: &str) -> Option<&FieldInfo> { + // self.fields.iter().find(|f| f.name == name).map(|f| *f) + // } + + // /// Retrieves the type's fields. + // pub fn get_fields(&self) -> impl Iterator { + // self.fields.iter().map(|f| *f) + // } + + /// Returns the module's functions. + pub fn functions(&self) -> &[FunctionInfo] { + if self.num_functions == 0 { + &[] + } else { + unsafe { slice::from_raw_parts(self.functions, self.num_functions as usize) } + } + } +} + +unsafe impl Send for ModuleInfo {} +unsafe impl Sync for ModuleInfo {} + +impl DispatchTable { + /// Returns an iterator over pairs of mutable function pointers and signatures. + pub fn iter_mut(&mut self) -> impl Iterator { + if self.num_entries == 0 { + (&mut []).iter_mut().zip((&[]).iter()) + } else { + let ptrs = + unsafe { slice::from_raw_parts_mut(self.fn_ptrs, self.num_entries as usize) }; + let signatures = + unsafe { slice::from_raw_parts(self.signatures, self.num_entries as usize) }; + + ptrs.iter_mut().zip(signatures.iter()) + } + } + + /// Returns mutable functions pointers. + pub fn ptrs_mut(&mut self) -> &mut [*const c_void] { + if self.num_entries == 0 { + &mut [] + } else { + unsafe { slice::from_raw_parts_mut(self.fn_ptrs, self.num_entries as usize) } + } + } + + /// Returns function signatures. + pub fn signatures(&self) -> &[FunctionSignature] { + if self.num_entries == 0 { + &[] + } else { + unsafe { slice::from_raw_parts(self.signatures, self.num_entries as usize) } + } + } + + /// Returns a function pointer, without doing bounds checking. + /// + /// This is generally not recommended, use with caution! Calling this method with an + /// out-of-bounds index is _undefined behavior_ even if the resulting reference is not used. + /// For a safe alternative see [get_ptr](#method.get_ptr). + pub unsafe fn get_ptr_unchecked(&self, idx: u32) -> *const c_void { + *self.fn_ptrs.offset(idx as isize) + } + + /// Returns a function pointer at the given index, or `None` if out of bounds. + pub fn get_ptr(&self, idx: u32) -> Option<*const c_void> { + if idx < self.num_entries { + Some(unsafe { self.get_ptr_unchecked(idx) }) + } else { + None + } + } + + /// Returns a mutable reference to a function pointer, without doing bounds checking. + /// + /// This is generally not recommended, use with caution! Calling this method with an + /// out-of-bounds index is _undefined behavior_ even if the resulting reference is not used. + /// For a safe alternative see [get_ptr_mut](#method.get_ptr_mut). + pub unsafe fn get_ptr_unchecked_mut(&self, idx: u32) -> &mut *const c_void { + &mut *self.fn_ptrs.offset(idx as isize) + } + + /// Returns a mutable reference to a function pointer at the given index, or `None` if out of + /// bounds. + pub fn get_ptr_mut(&self, idx: u32) -> Option<&mut *const c_void> { + if idx < self.num_entries { + Some(unsafe { self.get_ptr_unchecked_mut(idx) }) + } else { + None + } + } +} + +impl AssemblyInfo { + /// Returns an iterator over the assembly's dependencies. + pub fn dependencies(&self) -> impl Iterator { + let dependencies = if self.num_dependencies == 0 { + &[] + } else { + unsafe { slice::from_raw_parts(self.dependencies, self.num_dependencies as usize) } + }; + + dependencies.iter().map(|d| { + unsafe { CStr::from_ptr(*d) } + .to_str() + .expect("dependency path contains invalid UTF8") + }) + } +} + +unsafe impl Send for AssemblyInfo {} +unsafe impl Sync for AssemblyInfo {} + +#[cfg(test)] +mod tests { + use super::*; + use std::ffi::CString; + use std::os::raw::c_char; + use std::ptr; + + fn fake_type_info(name: &CStr) -> TypeInfo { + TypeInfo { + guid: FAKE_TYPE_GUID, + name: name.as_ptr(), + } + } + + const FAKE_TYPE_GUID: Guid = Guid { + b: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], + }; + + const FAKE_TYPE_NAME: &'static str = "type-name"; + + #[test] + fn test_type_info_name() { + let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name."); + let type_info = fake_type_info(&type_name); + + assert_eq!(type_info.name(), FAKE_TYPE_NAME); + } + + #[test] + fn test_type_info_eq() { + let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name."); + let type_info = fake_type_info(&type_name); + + assert_eq!(type_info, type_info); + } + + fn fake_fn_signature( + name: &CStr, + arg_types: &[TypeInfo], + return_type: Option<&TypeInfo>, + privacy: Privacy, + ) -> FunctionSignature { + FunctionSignature { + name: name.as_ptr(), + arg_types: arg_types.as_ptr(), + return_type: return_type.map_or(ptr::null(), |t| t as *const TypeInfo), + num_arg_types: arg_types.len() as u16, + privacy, + } + } + + const FAKE_FN_NAME: &'static str = "fn-name"; + + #[test] + fn test_fn_signature_name() { + let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); + let fn_signature = fake_fn_signature(&fn_name, &[], None, Privacy::Public); + + assert_eq!(fn_signature.name(), FAKE_FN_NAME); + } + + #[test] + fn test_fn_signature_privacy() { + let privacy = Privacy::Private; + let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); + let fn_signature = fake_fn_signature(&fn_name, &[], None, privacy); + + assert_eq!(fn_signature.privacy(), privacy); + } + + #[test] + fn test_fn_signature_arg_types_none() { + let arg_types = &[]; + let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); + let fn_signature = fake_fn_signature(&fn_name, arg_types, None, Privacy::Public); + + assert_eq!(fn_signature.arg_types(), arg_types); + } + + #[test] + fn test_fn_signature_arg_types_some() { + let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name."); + let type_info = fake_type_info(&type_name); + + let arg_types = &[type_info]; + let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); + let fn_signature = fake_fn_signature(&fn_name, arg_types, None, Privacy::Public); + + assert_eq!(fn_signature.arg_types(), arg_types); + } + + #[test] + fn test_fn_signature_return_type_none() { + let return_type = None; + let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); + let fn_signature = fake_fn_signature(&fn_name, &[], return_type, Privacy::Public); + + assert_eq!(fn_signature.return_type(), return_type); + } + + #[test] + fn test_fn_signature_return_type_some() { + let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name."); + let type_info = fake_type_info(&type_name); + + let return_type = Some(&type_info); + let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); + let fn_signature = fake_fn_signature(&fn_name, &[], return_type, Privacy::Public); + + assert_eq!(fn_signature.return_type(), return_type); + } + + fn fake_module_info(path: &CStr, functions: &[FunctionInfo]) -> ModuleInfo { + ModuleInfo { + path: path.as_ptr(), + functions: functions.as_ptr(), + num_functions: functions.len() as u32, + } + } + + const FAKE_MODULE_PATH: &'static str = "path::to::module"; + + #[test] + fn test_module_info_path() { + let module_path = CString::new(FAKE_MODULE_PATH).expect("Invalid fake module path."); + let module = fake_module_info(&module_path, &[]); + + assert_eq!(module.path(), FAKE_MODULE_PATH); + } + + #[test] + fn test_module_info_functions_none() { + let functions = &[]; + let module_path = CString::new(FAKE_MODULE_PATH).expect("Invalid fake module path."); + let module = fake_module_info(&module_path, functions); + + assert_eq!(module.functions().len(), functions.len()); + } + + #[test] + fn test_module_info_functions_some() { + let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name."); + let type_info = fake_type_info(&type_name); + + let return_type = Some(&type_info); + let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); + let fn_signature = fake_fn_signature(&fn_name, &[], return_type, Privacy::Public); + + let fn_info = FunctionInfo { + signature: fn_signature, + fn_ptr: ptr::null(), + }; + + let functions = &[fn_info]; + let module_path = CString::new(FAKE_MODULE_PATH).expect("Invalid fake module path."); + let module = fake_module_info(&module_path, functions); + + let result = module.functions(); + assert_eq!(result.len(), functions.len()); + for (lhs, rhs) in result.iter().zip(functions.iter()) { + assert_eq!(lhs.fn_ptr, rhs.fn_ptr); + assert_eq!(lhs.signature.name(), rhs.signature.name()); + assert_eq!(lhs.signature.arg_types(), rhs.signature.arg_types()); + assert_eq!(lhs.signature.return_type(), rhs.signature.return_type()); + assert_eq!(lhs.signature.privacy(), rhs.signature.privacy()); + } + } + + fn fake_dispatch_table( + fn_signatures: &[FunctionSignature], + fn_ptrs: &mut [*const c_void], + ) -> DispatchTable { + assert!(fn_signatures.len() == fn_ptrs.len()); + + DispatchTable { + signatures: fn_signatures.as_ptr(), + fn_ptrs: fn_ptrs.as_mut_ptr(), + num_entries: fn_signatures.len() as u32, + } + } + + #[test] + fn test_dispatch_table_iter_mut_none() { + let signatures = &[]; + let fn_ptrs = &mut []; + let mut dispatch_table = fake_dispatch_table(signatures, fn_ptrs); + + let iter = fn_ptrs.iter_mut().zip(signatures.iter()); + assert_eq!(dispatch_table.iter_mut().count(), iter.count()); + } + + #[test] + fn test_dispatch_table_iter_mut_some() { + let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name."); + let type_info = fake_type_info(&type_name); + + let return_type = Some(&type_info); + let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); + let fn_signature = fake_fn_signature(&fn_name, &[], return_type, Privacy::Public); + + let signatures = &[fn_signature]; + let fn_ptrs = &mut [ptr::null()]; + let mut dispatch_table = fake_dispatch_table(signatures, fn_ptrs); + + let iter = fn_ptrs.iter_mut().zip(signatures.iter()); + assert_eq!(dispatch_table.iter_mut().count(), iter.len()); + + for (lhs, rhs) in dispatch_table.iter_mut().zip(iter) { + assert_eq!(lhs.0, rhs.0); + assert_eq!(lhs.1.name(), rhs.1.name()); + assert_eq!(lhs.1.arg_types(), rhs.1.arg_types()); + assert_eq!(lhs.1.return_type(), rhs.1.return_type()); + assert_eq!(lhs.1.privacy(), rhs.1.privacy()); + } + } + + #[test] + fn test_dispatch_table_ptrs_mut() { + let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name."); + let type_info = fake_type_info(&type_name); + + let return_type = Some(&type_info); + let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); + let fn_signature = fake_fn_signature(&fn_name, &[], return_type, Privacy::Public); + + let signatures = &[fn_signature]; + let fn_ptrs = &mut [ptr::null()]; + let mut dispatch_table = fake_dispatch_table(signatures, fn_ptrs); + + let result = dispatch_table.ptrs_mut(); + assert_eq!(result.len(), fn_ptrs.len()); + for (lhs, rhs) in result.iter().zip(fn_ptrs.iter()) { + assert_eq!(lhs, rhs); + } + } + + #[test] + fn test_dispatch_table_signatures() { + let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name."); + let type_info = fake_type_info(&type_name); + + let return_type = Some(&type_info); + let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); + let fn_signature = fake_fn_signature(&fn_name, &[], return_type, Privacy::Public); + + let signatures = &[fn_signature]; + let fn_ptrs = &mut [ptr::null()]; + let dispatch_table = fake_dispatch_table(signatures, fn_ptrs); + + let result = dispatch_table.signatures(); + assert_eq!(result.len(), signatures.len()); + for (lhs, rhs) in result.iter().zip(signatures.iter()) { + assert_eq!(lhs.name(), rhs.name()); + assert_eq!(lhs.arg_types(), rhs.arg_types()); + assert_eq!(lhs.return_type(), rhs.return_type()); + assert_eq!(lhs.privacy(), rhs.privacy()); + } + } + + #[test] + fn test_dispatch_table_get_ptr_unchecked() { + let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name."); + let type_info = fake_type_info(&type_name); + + let return_type = Some(&type_info); + let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); + let fn_signature = fake_fn_signature(&fn_name, &[], return_type, Privacy::Public); + + let signatures = &[fn_signature]; + let fn_ptrs = &mut [ptr::null()]; + + let dispatch_table = fake_dispatch_table(signatures, fn_ptrs); + assert_eq!(unsafe { dispatch_table.get_ptr_unchecked(0) }, fn_ptrs[0]); + } + + #[test] + fn test_dispatch_table_get_ptr_none() { + let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name."); + let type_info = fake_type_info(&type_name); + + let return_type = Some(&type_info); + let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); + let fn_signature = fake_fn_signature(&fn_name, &[], return_type, Privacy::Public); + + let signatures = &[fn_signature]; + let fn_ptrs = &mut [ptr::null()]; + + let dispatch_table = fake_dispatch_table(signatures, fn_ptrs); + assert_eq!(dispatch_table.get_ptr(1), None); + } + + #[test] + fn test_dispatch_table_get_ptr_some() { + let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name."); + let type_info = fake_type_info(&type_name); + + let return_type = Some(&type_info); + let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); + let fn_signature = fake_fn_signature(&fn_name, &[], return_type, Privacy::Public); + + let signatures = &[fn_signature]; + let fn_ptrs = &mut [ptr::null()]; + + let dispatch_table = fake_dispatch_table(signatures, fn_ptrs); + assert_eq!(dispatch_table.get_ptr(0), Some(fn_ptrs[0])); + } + + #[test] + fn test_dispatch_table_get_ptr_unchecked_mut() { + let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name."); + let type_info = fake_type_info(&type_name); + + let return_type = Some(&type_info); + let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); + let fn_signature = fake_fn_signature(&fn_name, &[], return_type, Privacy::Public); + + let signatures = &[fn_signature]; + let fn_ptrs = &mut [ptr::null()]; + + let dispatch_table = fake_dispatch_table(signatures, fn_ptrs); + assert_eq!( + unsafe { dispatch_table.get_ptr_unchecked_mut(0) }, + &mut fn_ptrs[0] + ); + } + + #[test] + fn test_dispatch_table_get_ptr_mut_none() { + let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name."); + let type_info = fake_type_info(&type_name); + + let return_type = Some(&type_info); + let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); + let fn_signature = fake_fn_signature(&fn_name, &[], return_type, Privacy::Public); + + let signatures = &[fn_signature]; + let fn_ptrs = &mut [ptr::null()]; + + let dispatch_table = fake_dispatch_table(signatures, fn_ptrs); + assert_eq!(dispatch_table.get_ptr_mut(1), None); + } + + #[test] + fn test_dispatch_table_get_ptr_mut_some() { + let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name."); + let type_info = fake_type_info(&type_name); + + let return_type = Some(&type_info); + let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name."); + let fn_signature = fake_fn_signature(&fn_name, &[], return_type, Privacy::Public); + + let signatures = &[fn_signature]; + let fn_ptrs = &mut [ptr::null()]; + + let dispatch_table = fake_dispatch_table(signatures, fn_ptrs); + assert_eq!(dispatch_table.get_ptr_mut(0), Some(&mut fn_ptrs[0])); + } + + fn fake_assembly_info( + symbols: ModuleInfo, + dispatch_table: DispatchTable, + dependencies: &[*const c_char], + ) -> AssemblyInfo { + AssemblyInfo { + symbols, + dispatch_table, + dependencies: dependencies.as_ptr(), + num_dependencies: dependencies.len() as u32, + } + } + + const FAKE_DEPENDENCY: &'static str = "path/to/dependency.dylib"; + + #[test] + fn test_assembly_info_dependencies() { + let module_path = CString::new(FAKE_MODULE_PATH).expect("Invalid fake module path."); + let module = fake_module_info(&module_path, &[]); + + let dispatch_table = fake_dispatch_table(&[], &mut []); + + let dependency = CString::new(FAKE_DEPENDENCY).expect("Invalid fake dependency."); + let dependencies = &[dependency.as_ptr()]; + let assembly = fake_assembly_info(module, dispatch_table, dependencies); + + assert_eq!(assembly.dependencies().count(), dependencies.len()); + for (lhs, rhs) in assembly.dependencies().zip([FAKE_DEPENDENCY].iter()) { + assert_eq!(lhs, *rhs) + } + } +} diff --git a/crates/mun_abi/src/lib.rs b/crates/mun_abi/src/lib.rs index 998fe9e5c..3a4f37c27 100644 --- a/crates/mun_abi/src/lib.rs +++ b/crates/mun_abi/src/lib.rs @@ -1,4 +1,7 @@ +// Bindings are automatically generated from C on `cargo build` mod autogen; + +mod autogen_impl; mod macros; mod reflection; diff --git a/crates/mun_runtime/src/macros.rs b/crates/mun_runtime/src/macros.rs index 0cd6f8805..5cc79a88f 100644 --- a/crates/mun_runtime/src/macros.rs +++ b/crates/mun_runtime/src/macros.rs @@ -56,7 +56,7 @@ macro_rules! invoke_fn_impl { while !err.runtime.update() { // Wait until there has been an update that might fix the error } - err.runtime.$FnName(err.function_name, $(err.$Arg,)*) + $crate::MunRuntime::$FnName(err.runtime, err.function_name, $(err.$Arg,)*) } } } @@ -78,18 +78,18 @@ macro_rules! invoke_fn_impl { /// If an error occurs when invoking the method, an error message is logged. The /// runtime continues looping until the cause of the error has been resolved. pub fn $FnName<'r, 's, $($T: Reflection,)* Output: Reflection>( - &'r mut self, + runtime: &'r mut MunRuntime, function_name: &'s str, $($Arg: $T,)* ) -> core::result::Result> { - let function: core::result::Result Output, String> = self + let function: core::result::Result Output, String> = runtime .get_function_info(function_name) .ok_or(format!("Failed to obtain function '{}'", function_name)) .and_then(|function| mun_abi::downcast_fn!(function, fn($($T),*) -> Output)); match function { Ok(function) => Ok(function($($Arg),*)), - Err(e) => Err($ErrName::new(e, self, function_name, $($Arg),*)), + Err(e) => Err($ErrName::new(e, runtime, function_name, $($Arg),*)), } } } @@ -100,42 +100,59 @@ macro_rules! invoke_fn_impl { #[macro_export] macro_rules! invoke_fn { ($Runtime:expr, $FnName:expr) => { - $Runtime.invoke_fn0($FnName) + $crate::MunRuntime::invoke_fn0(&mut $Runtime, $FnName) }; ($Runtime:expr, $FnName:expr, $A:expr) => { - $Runtime.invoke_fn1($FnName, $A) + $crate::MunRuntime::invoke_fn1(&mut $Runtime, $FnName, $A) }; ($Runtime:expr, $FnName:expr, $A:expr, $B:expr) => { - $Runtime.invoke_fn2($FnName, $A, $B) + $crate::MunRuntime::invoke_fn2(&mut $Runtime, $FnName, $A, $B) }; ($Runtime:expr, $FnName:expr, $A:expr, $B:expr, $C:expr) => { - $Runtime.invoke_fn3($FnName, $A, $B, $C) + $crate::MunRuntime::invoke_fn3(&mut $Runtime, $FnName, $A, $B, $C) }; ($Runtime:expr, $FnName:expr, $A:expr, $B:expr, $C:expr, $D:expr) => { - $Runtime.invoke_fn4($FnName, $A, $B, $C, $D) + $crate::MunRuntime::invoke_fn4(&mut $Runtime, $FnName, $A, $B, $C, $D) }; ($Runtime:expr, $FnName:expr, $A:expr, $B:expr, $C:expr, $D:expr, $E:expr) => { - $Runtime.invoke_fn5($FnName, $A, $B, $C, $D, $E) + $crate::MunRuntime::invoke_fn5(&mut $Runtime, $FnName, $A, $B, $C, $D, $E) }; ($Runtime:expr, $FnName:expr, $A:expr, $B:expr, $C:expr, $D:expr, $E:expr, $F:expr) => { - $Runtime.invoke_fn6($FnName, $A, $B, $C, $D, $E, $F) + $crate::MunRuntime::invoke_fn6(&mut $Runtime, $FnName, $A, $B, $C, $D, $E, $F) }; ($Runtime:expr, $FnName:expr, $A:expr, $B:expr, $C:expr, $D:expr, $E:expr, $F:expr, $G:expr) => { - $Runtime.invoke_fn7($FnName, $A, $B, $C, $D, $E, $F, $G) + $crate::MunRuntime::invoke_fn7(&mut $Runtime, $FnName, $A, $B, $C, $D, $E, $F, $G) }; ($Runtime:expr, $FnName:expr, $A:expr, $B:expr, $C:expr, $D:expr, $E:expr, $F:expr, $G:expr, $H:expr) => { - $Runtime.invoke_fn8($FnName, $A, $B, $C, $D, $E, $F, $G, $H) + $crate::MunRuntime::invoke_fn8(&mut $Runtime, $FnName, $A, $B, $C, $D, $E, $F, $G, $H) }; ($Runtime:expr, $FnName:expr, $A:expr, $B:expr, $C:expr, $D:expr, $E:expr, $F:expr, $G:expr, $H:expr, $I:expr) => { - $Runtime.invoke_fn9($FnName, $A, $B, $C, $D, $E, $F, $G, $H, $I) + $crate::MunRuntime::invoke_fn9(&mut $Runtime, $FnName, $A, $B, $C, $D, $E, $F, $G, $H, $I) }; ($Runtime:expr, $FnName:expr, $A:expr, $B:expr, $C:expr, $D:expr, $E:expr, $F:expr, $G:expr, $H:expr, $I:expr, $J:expr) => { - $Runtime.invoke_fn10($FnName, $A, $B, $C, $D, $E, $F, $G, $H, $I, $J) + $crate::MunRuntime::invoke_fn10( + &mut $Runtime, + $FnName, + $A, + $B, + $C, + $D, + $E, + $F, + $G, + $H, + $I, + $J, + ) }; ($Runtime:expr, $FnName:expr, $A:expr, $B:expr, $C:expr, $D:expr, $E:expr, $F:expr, $G:expr, $H:expr, $I:expr, $J:expr, $K:expr) => { - $Runtime.invoke_fn11($FnName, $A, $B, $C, $D, $E, $F, $G, $H, $I, $J, $K) + $crate::MunRuntime::invoke_fn11( + $Runtime, $FnName, $A, $B, $C, $D, $E, $F, $G, $H, $I, $J, $K, + ) }; ($Runtime:expr, $FnName:expr, $A:expr, $B:expr, $C:expr, $D:expr, $E:expr, $F:expr, $G:expr, $H:expr, $I:expr, $J:expr, $K:expr, $L:expr) => { - $Runtime.invoke_fn12($FnName, $A, $B, $C, $D, $E, $F, $G, $H, $I, $J, $K, $L) + $crate::MunRuntime::invoke_fn12( + $Runtime, $FnName, $A, $B, $C, $D, $E, $F, $G, $H, $I, $J, $K, $L, + ) }; } diff --git a/crates/mun_runtime_capi/Cargo.toml b/crates/mun_runtime_capi/Cargo.toml new file mode 100644 index 000000000..ea17c1398 --- /dev/null +++ b/crates/mun_runtime_capi/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "mun_runtime_capi" +version = "0.1.0" +authors = ["Wodann "] +edition = "2018" + +[dependencies] +mun_abi = { path = "../mun_abi" } +mun_runtime = { path = "../mun_runtime" } + +[build-dependencies] +cbindgen = "0.9.1" diff --git a/crates/mun_runtime_capi/build.rs b/crates/mun_runtime_capi/build.rs new file mode 100644 index 000000000..9f6b92e6d --- /dev/null +++ b/crates/mun_runtime_capi/build.rs @@ -0,0 +1,11 @@ +use std::env; + +use cbindgen; + +fn main() { + let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + + cbindgen::generate(crate_dir) + .expect("Unable to generate Mun Runtime bindings.") + .write_to_file("c/include/mun_runtime.h"); +} diff --git a/crates/mun_runtime_capi/c b/crates/mun_runtime_capi/c new file mode 160000 index 000000000..f9d3d6c3b --- /dev/null +++ b/crates/mun_runtime_capi/c @@ -0,0 +1 @@ +Subproject commit f9d3d6c3b9c8bd0cc38279b85dfcc3debdc34b07 diff --git a/crates/mun_runtime_capi/cbindgen.toml b/crates/mun_runtime_capi/cbindgen.toml new file mode 100644 index 000000000..3e4409a8e --- /dev/null +++ b/crates/mun_runtime_capi/cbindgen.toml @@ -0,0 +1,17 @@ +language = "C" +cpp_compat = true + +include_guard = "MUN_RUNTIME_BINDINGS_H_" +include_version = true +sys_includes = ["stdbool.h", "stdint.h"] +no_includes = true + +line_length = 100 +tab_width = 4 + +[export] +prefix = "Mun" + +[parse] +parse_deps = true +include = ["mun_abi"] diff --git a/crates/mun_runtime_capi/src/lib.rs b/crates/mun_runtime_capi/src/lib.rs new file mode 100644 index 000000000..5c4b06dab --- /dev/null +++ b/crates/mun_runtime_capi/src/lib.rs @@ -0,0 +1,94 @@ +use mun_abi::FunctionInfo; +use mun_runtime::{MunRuntime, RuntimeBuilder}; +use std::ffi::{c_void, CStr}; +use std::os::raw::c_char; + +#[repr(C)] +pub struct RuntimeHandle(*mut c_void); + +#[no_mangle] +pub extern "C" fn create_runtime(library_path: *const c_char, handle: *mut RuntimeHandle) -> u64 /* error */ +{ + if library_path.is_null() { + return 1; + } + + let library_path = match unsafe { CStr::from_ptr(library_path) }.to_str() { + Ok(path) => path, + Err(_) => return 2, + }; + + let handle = match unsafe { handle.as_mut() } { + Some(handle) => handle, + None => return 3, + }; + + let runtime = match RuntimeBuilder::new(library_path).spawn() { + Ok(runtime) => runtime, + Err(_) => return 4, + }; + + handle.0 = Box::into_raw(Box::new(runtime)) as *mut _; + 0 +} + +#[no_mangle] +pub extern "C" fn destroy_runtime(handle: RuntimeHandle) { + if !handle.0.is_null() { + let _runtime = unsafe { Box::from_raw(handle.0) }; + } +} + +#[no_mangle] +pub extern "C" fn runtime_get_function_info( + handle: RuntimeHandle, + fn_name: *const c_char, + has_fn_info: *mut bool, + fn_info: *mut FunctionInfo, +) -> u64 /* error */ { + let runtime = match unsafe { (handle.0 as *mut MunRuntime).as_ref() } { + Some(runtime) => runtime, + None => return 1, + }; + + let fn_name = match unsafe { CStr::from_ptr(fn_name) }.to_str() { + Ok(name) => name, + Err(_) => return 2, + }; + + let has_fn_info = match unsafe { has_fn_info.as_mut() } { + Some(has_info) => has_info, + None => return 3, + }; + + let fn_info = match unsafe { fn_info.as_mut() } { + Some(info) => info, + None => return 4, + }; + + match runtime.get_function_info(fn_name) { + Some(info) => { + *has_fn_info = true; + *fn_info = info.clone(); + } + None => *has_fn_info = false, + } + + 0 +} + +#[no_mangle] +pub extern "C" fn runtime_update(handle: RuntimeHandle, updated: *mut bool) -> u64 /* error */ { + let runtime = match unsafe { (handle.0 as *mut MunRuntime).as_mut() } { + Some(runtime) => runtime, + None => return 1, + }; + + let updated = match unsafe { updated.as_mut() } { + Some(updated) => updated, + None => return 2, + }; + + *updated = runtime.update(); + 0 +}