From 4d8739bcb4d8dd83ba8bad067b6b53a3547ff412 Mon Sep 17 00:00:00 2001 From: Wodann Date: Sun, 27 Oct 2019 12:44:05 +0100 Subject: [PATCH 01/11] feat(runtime_capi): add automatic generation of C++ bindings for the runtime --- .gitmodules | 3 +++ crates/mun_runtime_capi/build.rs | 6 +++--- crates/mun_runtime_capi/cpp | 1 + 3 files changed, 7 insertions(+), 3 deletions(-) create mode 160000 crates/mun_runtime_capi/cpp diff --git a/.gitmodules b/.gitmodules index a694cec89..2218aef14 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "crates/mun_runtime_capi/c"] path = crates/mun_runtime_capi/c url = ../../mun-lang/runtime-c.git +[submodule "crates/mun_runtime_capi/cpp"] + path = crates/mun_runtime_capi/cpp + url = ../../mun-lang/runtime-cpp.git diff --git a/crates/mun_runtime_capi/build.rs b/crates/mun_runtime_capi/build.rs index 9f6b92e6d..b9af05b20 100644 --- a/crates/mun_runtime_capi/build.rs +++ b/crates/mun_runtime_capi/build.rs @@ -5,7 +5,7 @@ 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"); + let bindings = cbindgen::generate(crate_dir).expect("Unable to generate Mun Runtime bindings."); + bindings.write_to_file("c/include/mun/runtime.h"); + bindings.write_to_file("cpp/include/mun/runtime_capi.h"); } diff --git a/crates/mun_runtime_capi/cpp b/crates/mun_runtime_capi/cpp new file mode 160000 index 000000000..7ee823c3c --- /dev/null +++ b/crates/mun_runtime_capi/cpp @@ -0,0 +1 @@ +Subproject commit 7ee823c3c09f6bba84981704f27df606e9458c79 From ec9e551ec697939ee7a0418348d0240d6edab660 Mon Sep 17 00:00:00 2001 From: Wodann Date: Sun, 27 Oct 2019 12:47:45 +0100 Subject: [PATCH 02/11] fix(runtime): incorrect order of execution when unloading shared libraries --- crates/mun_runtime/Cargo.toml | 1 - crates/mun_runtime/src/assembly.rs | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/crates/mun_runtime/Cargo.toml b/crates/mun_runtime/Cargo.toml index 8b4fc115b..f3e9ec208 100644 --- a/crates/mun_runtime/Cargo.toml +++ b/crates/mun_runtime/Cargo.toml @@ -5,7 +5,6 @@ authors = ["Wodann "] edition = "2018" [dependencies] -cargo = "0.37" failure = "0.1.5" libloading = "0.5" mun_abi = { path = "../mun_abi" } diff --git a/crates/mun_runtime/src/assembly.rs b/crates/mun_runtime/src/assembly.rs index 38df7026a..2554786e4 100644 --- a/crates/mun_runtime/src/assembly.rs +++ b/crates/mun_runtime/src/assembly.rs @@ -71,14 +71,14 @@ impl Assembly { ) -> Result<(), Error> { // let library_path = library_path.canonicalize()?; - // Drop the old library, as some operating systems don't allow editing of in-use shared - // libraries - self.library.take(); - for function in self.info.symbols.functions() { runtime_dispatch_table.remove(function.signature.name()); } + // Drop the old library, as some operating systems don't allow editing of in-use shared + // libraries + self.library.take(); + // TODO: Partial hot reload of an assembly *self = Assembly::load(library_path, runtime_dispatch_table)?; Ok(()) From a533cb1b9ad73d92753bd559298fbac373c7f3a3 Mon Sep 17 00:00:00 2001 From: Wodann Date: Sun, 27 Oct 2019 12:49:13 +0100 Subject: [PATCH 03/11] feat(runtime_capi): add error reporting --- crates/mun_runtime_capi/Cargo.toml | 8 +++ crates/mun_runtime_capi/c | 2 +- crates/mun_runtime_capi/src/error.rs | 39 ++++++++++++ crates/mun_runtime_capi/src/hub.rs | 71 +++++++++++++++++++++ crates/mun_runtime_capi/src/lib.rs | 95 +++++++++++++++++++++------- 5 files changed, 191 insertions(+), 24 deletions(-) create mode 100644 crates/mun_runtime_capi/src/error.rs create mode 100644 crates/mun_runtime_capi/src/hub.rs diff --git a/crates/mun_runtime_capi/Cargo.toml b/crates/mun_runtime_capi/Cargo.toml index ea17c1398..7db21787f 100644 --- a/crates/mun_runtime_capi/Cargo.toml +++ b/crates/mun_runtime_capi/Cargo.toml @@ -4,9 +4,17 @@ version = "0.1.0" authors = ["Wodann "] edition = "2018" +[lib] +name = "mun_runtime" +crate-type = ["cdylib"] + [dependencies] +failure = "0.1.5" +lazy_static = "1.4.0" mun_abi = { path = "../mun_abi" } mun_runtime = { path = "../mun_runtime" } +parking_lot = "0.9.0" +rand = "0.7.2" [build-dependencies] cbindgen = "0.9.1" diff --git a/crates/mun_runtime_capi/c b/crates/mun_runtime_capi/c index f9d3d6c3b..86c314e1b 160000 --- a/crates/mun_runtime_capi/c +++ b/crates/mun_runtime_capi/c @@ -1 +1 @@ -Subproject commit f9d3d6c3b9c8bd0cc38279b85dfcc3debdc34b07 +Subproject commit 86c314e1b1ecbdce76f52cd839e841cc6f91c5de diff --git a/crates/mun_runtime_capi/src/error.rs b/crates/mun_runtime_capi/src/error.rs new file mode 100644 index 000000000..30423d598 --- /dev/null +++ b/crates/mun_runtime_capi/src/error.rs @@ -0,0 +1,39 @@ +use std::ffi::CString; +use std::hash::Hash; +use std::os::raw::c_char; +use std::ptr; + +use crate::hub::HUB; +use crate::{Token, TypedHandle}; + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default, Hash, Eq, PartialEq)] +pub struct ErrorHandle(Token); + +impl TypedHandle for ErrorHandle { + fn new(token: Token) -> Self { + Self(token) + } + + fn token(&self) -> Token { + self.0 + } +} + +#[no_mangle] +pub extern "C" fn mun_error_destroy(error_handle: ErrorHandle) { + // If an error exists, destroy it + let _error = HUB.errors.unregister(error_handle); +} + +#[no_mangle] +pub extern "C" fn mun_error_message(error_handle: ErrorHandle) -> *const c_char { + let errors = HUB.errors.get_data(); + let error = match errors.get(&error_handle) { + Some(error) => error, + None => return ptr::null_mut(), + }; + + let message = format!("{}", error); + CString::new(message).unwrap().into_raw() as *const _ +} diff --git a/crates/mun_runtime_capi/src/hub.rs b/crates/mun_runtime_capi/src/hub.rs new file mode 100644 index 000000000..1bebfe043 --- /dev/null +++ b/crates/mun_runtime_capi/src/hub.rs @@ -0,0 +1,71 @@ +use std::collections::HashMap; +use std::hash::Hash; +use std::sync::Arc; + +use failure::Error; +use lazy_static::lazy_static; +use parking_lot::{RwLock, RwLockReadGuard}; + +use crate::error::ErrorHandle; +use crate::TypedHandle; + +fn generate_handle() -> H { + loop { + let token = rand::random(); + if token != 0 { + return H::new(token); + } + } +} + +pub struct Registry { + data: RwLock>, +} + +impl Registry +where + H: Copy + Eq + Hash + TypedHandle, +{ + pub fn register(&self, value: T) -> H { + let handle = { + let data = self.data.read(); + + let mut handle = generate_handle(); + while data.contains_key(&handle) { + handle = generate_handle(); + } + handle + }; + + self.data.write().insert(handle, value); + handle + } + + pub fn unregister(&self, handle: H) -> Option { + self.data.write().remove(&handle) + } + + pub fn get_data(&self) -> RwLockReadGuard> { + self.data.read() + } +} + +impl Default for Registry +where + H: Eq + Hash + TypedHandle, +{ + fn default() -> Self { + Registry { + data: RwLock::new(HashMap::new()), + } + } +} + +#[derive(Default)] +pub struct Hub { + pub errors: Arc>>, +} + +lazy_static! { + pub static ref HUB: Hub = Hub::default(); +} diff --git a/crates/mun_runtime_capi/src/lib.rs b/crates/mun_runtime_capi/src/lib.rs index 8c0a9864e..af273d5c4 100644 --- a/crates/mun_runtime_capi/src/lib.rs +++ b/crates/mun_runtime_capi/src/lib.rs @@ -1,72 +1,111 @@ -use mun_abi::FunctionInfo; -use mun_runtime::{MunRuntime, RuntimeBuilder}; +mod error; +mod hub; + use std::ffi::{c_void, CStr}; use std::os::raw::c_char; +use crate::error::ErrorHandle; +use crate::hub::HUB; +use failure::err_msg; +use mun_abi::FunctionInfo; +use mun_runtime::{MunRuntime, RuntimeBuilder}; + +pub(crate) type Token = usize; + +pub trait TypedHandle { + fn new(token: Token) -> Self; + fn token(&self) -> Token; +} + #[repr(C)] pub struct RuntimeHandle(*mut c_void); #[no_mangle] -pub unsafe extern "C" fn create_runtime( +pub unsafe extern "C" fn mun_runtime_create( library_path: *const c_char, handle: *mut RuntimeHandle, -) -> u64 /* error */ -{ +) -> ErrorHandle { if library_path.is_null() { - return 1; + return HUB.errors.register(Box::new(err_msg( + "Invalid argument: 'library_path' is null pointer.", + ))); } let library_path = match CStr::from_ptr(library_path).to_str() { Ok(path) => path, - Err(_) => return 2, + Err(_) => { + return HUB.errors.register(Box::new(err_msg( + "Invalid argument: 'library_path' is not UTF-8 encoded.", + ))) + } }; let handle = match handle.as_mut() { Some(handle) => handle, - None => return 3, + None => { + return HUB.errors.register(Box::new(err_msg( + "Invalid argument: 'handle' is null pointer.", + ))) + } }; let runtime = match RuntimeBuilder::new(library_path).spawn() { Ok(runtime) => runtime, - Err(_) => return 4, + Err(e) => return HUB.errors.register(Box::new(e)), }; handle.0 = Box::into_raw(Box::new(runtime)) as *mut _; - 0 + ErrorHandle::default() } #[no_mangle] -pub extern "C" fn destroy_runtime(handle: RuntimeHandle) { +pub extern "C" fn mun_runtime_destroy(handle: RuntimeHandle) { if !handle.0.is_null() { let _runtime = unsafe { Box::from_raw(handle.0) }; } } #[no_mangle] -pub unsafe extern "C" fn runtime_get_function_info( +pub unsafe extern "C" fn mun_runtime_get_function_info( handle: RuntimeHandle, fn_name: *const c_char, has_fn_info: *mut bool, fn_info: *mut FunctionInfo, -) -> u64 /* error */ { +) -> ErrorHandle { let runtime = match (handle.0 as *mut MunRuntime).as_ref() { Some(runtime) => runtime, - None => return 1, + None => { + return HUB.errors.register(Box::new(err_msg( + "Invalid argument: 'runtime' is null pointer.", + ))) + } }; let fn_name = match CStr::from_ptr(fn_name).to_str() { Ok(name) => name, - Err(_) => return 2, + Err(_) => { + return HUB.errors.register(Box::new(err_msg( + "Invalid argument: 'fn_name' is not UTF-8 encoded.", + ))) + } }; let has_fn_info = match has_fn_info.as_mut() { Some(has_info) => has_info, - None => return 3, + None => { + return HUB.errors.register(Box::new(err_msg( + "Invalid argument: 'has_fn_info' is null pointer.", + ))) + } }; let fn_info = match fn_info.as_mut() { Some(info) => info, - None => return 4, + None => { + return HUB.errors.register(Box::new(err_msg( + "Invalid argument: 'fn_info' is null pointer.", + ))) + } }; match runtime.get_function_info(fn_name) { @@ -77,22 +116,32 @@ pub unsafe extern "C" fn runtime_get_function_info( None => *has_fn_info = false, } - 0 + ErrorHandle::default() } #[no_mangle] -pub unsafe extern "C" fn runtime_update(handle: RuntimeHandle, updated: *mut bool) -> u64 /* error */ -{ +pub unsafe extern "C" fn mun_runtime_update( + handle: RuntimeHandle, + updated: *mut bool, +) -> ErrorHandle { let runtime = match (handle.0 as *mut MunRuntime).as_mut() { Some(runtime) => runtime, - None => return 1, + None => { + return HUB.errors.register(Box::new(err_msg( + "Invalid argument: 'runtime' is null pointer.", + ))) + } }; let updated = match updated.as_mut() { Some(updated) => updated, - None => return 2, + None => { + return HUB.errors.register(Box::new(err_msg( + "Invalid argument: 'updated' is null pointer.", + ))) + } }; *updated = runtime.update(); - 0 + ErrorHandle::default() } From cd2d0f79d7323c69e25f6527fca658bd60dfdbb8 Mon Sep 17 00:00:00 2001 From: Wodann Date: Wed, 30 Oct 2019 13:50:33 +0100 Subject: [PATCH 04/11] doc(abi): add missing docs The mun_abi crate now warns when there are missing docs. --- crates/mun_abi/c | 2 +- crates/mun_abi/src/autogen.rs | 45 ++++++++++++++++++++++++++++++++--- crates/mun_abi/src/lib.rs | 11 +++++++++ 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/crates/mun_abi/c b/crates/mun_abi/c index 39f28db46..709318f7b 160000 --- a/crates/mun_abi/c +++ b/crates/mun_abi/c @@ -1 +1 @@ -Subproject commit 39f28db4644e9c2ea894b912f47cb0181cb4cbd5 +Subproject commit 709318f7bc8eaca2e920589b6f03c9ac2a95b4fa diff --git a/crates/mun_abi/src/autogen.rs b/crates/mun_abi/src/autogen.rs index 7e780a1d2..c44dfb0fb 100644 --- a/crates/mun_abi/src/autogen.rs +++ b/crates/mun_abi/src/autogen.rs @@ -3,10 +3,15 @@ #![allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] use crate::Privacy; -#[doc = "
"] +#[doc = " Represents a globally unique identifier (GUID)."] +#[doc = ""] +#[doc = " GUIDs are generated by taking the MD5 hash of a type's name."] +#[doc = ""] +#[doc = "
"] #[repr(C)] #[derive(Debug, Copy, Clone, PartialEq)] pub struct Guid { + #[doc = " 16-byte MD5 hash"] pub b: [u8; 16usize], } #[test] @@ -27,10 +32,15 @@ fn bindgen_test_layout_Guid() { concat!("Offset of field: ", stringify!(Guid), "::", stringify!(b)) ); } +#[doc = " Represents the type declaration for a value type."] +#[doc = ""] +#[doc = " TODO: add support for structs, polymorphism, enumerations, type parameters, generic type definitions, and constructed generic types."] #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct TypeInfo { + #[doc = " Type GUID"] pub guid: Guid, + #[doc = " Type name"] pub name: *const ::std::os::raw::c_char, } #[test] @@ -66,14 +76,21 @@ fn bindgen_test_layout_TypeInfo() { ) ); } -#[doc = "
"] +#[doc = " Represents a function signature."] +#[doc = ""] +#[doc = "
"] #[repr(C)] #[derive(Clone)] pub struct FunctionSignature { + #[doc = " Function name"] pub name: *const ::std::os::raw::c_char, + #[doc = " Argument types"] pub arg_types: *const TypeInfo, + #[doc = " Optional return type"] pub return_type: *const TypeInfo, + #[doc = " Number of argument types"] pub num_arg_types: u16, + #[doc = " Function accessibility level"] pub privacy: Privacy, } #[test] @@ -139,11 +156,17 @@ fn bindgen_test_layout_FunctionSignature() { ) ); } -#[doc = "
"] +#[doc = " Represents a function declaration."] +#[doc = ""] +#[doc = " `fn_ptr` can be used to call the declared function."] +#[doc = ""] +#[doc = "
"] #[repr(C)] #[derive(Clone)] pub struct FunctionInfo { + #[doc = " Function signature"] pub signature: FunctionSignature, + #[doc = " Function pointer"] pub fn_ptr: *const ::std::os::raw::c_void, } #[test] @@ -179,11 +202,15 @@ fn bindgen_test_layout_FunctionInfo() { ) ); } +#[doc = " Represents a module declaration."] #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct ModuleInfo { + #[doc = " Module path"] pub path: *const ::std::os::raw::c_char, + #[doc = " Module functions"] pub functions: *const FunctionInfo, + #[doc = " Number of module functions"] pub num_functions: u32, } #[test] @@ -229,11 +256,18 @@ fn bindgen_test_layout_ModuleInfo() { ) ); } +#[doc = " Represents a function dispatch table. This is used for runtime linking."] +#[doc = ""] +#[doc = " Function signatures and pointers are stored separately for cache efficiency."] +#[doc = ""] #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct DispatchTable { + #[doc = " Function signatures"] pub signatures: *const FunctionSignature, + #[doc = " Function pointers"] pub fn_ptrs: *mut *const ::std::os::raw::c_void, + #[doc = " Number of functions"] pub num_entries: u32, } #[test] @@ -279,12 +313,17 @@ fn bindgen_test_layout_DispatchTable() { ) ); } +#[doc = " Represents an assembly declaration."] #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct AssemblyInfo { + #[doc = " Symbols of the top-level module"] pub symbols: ModuleInfo, + #[doc = " Dispatch table"] pub dispatch_table: DispatchTable, + #[doc = " Paths to assembly dependencies"] pub dependencies: *const *const ::std::os::raw::c_char, + #[doc = " Number of dependencies"] pub num_dependencies: u32, } #[test] diff --git a/crates/mun_abi/src/lib.rs b/crates/mun_abi/src/lib.rs index 3a4f37c27..587548fb7 100644 --- a/crates/mun_abi/src/lib.rs +++ b/crates/mun_abi/src/lib.rs @@ -1,3 +1,9 @@ +//! The Mun ABI +//! +//! The Mun ABI defines the binary format used to communicate between the Mun Compiler and Mun +//! Runtime. +#![warn(missing_docs)] + // Bindings are automatically generated from C on `cargo build` mod autogen; @@ -8,6 +14,9 @@ mod reflection; pub use autogen::*; pub use reflection::Reflection; +/// The Mun ABI prelude +/// +/// The *prelude* contains imports that are used almost every time. pub mod prelude { pub use crate::autogen::*; pub use crate::reflection::Reflection; @@ -18,6 +27,8 @@ pub mod prelude { #[repr(u8)] #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Privacy { + /// Publicly (and privately) accessible Public = 0, + /// Privately accessible Private = 1, } From 1287e75ac6de38089daf59043784452c404d51e7 Mon Sep 17 00:00:00 2001 From: Wodann Date: Wed, 30 Oct 2019 17:56:06 +0100 Subject: [PATCH 05/11] doc(runtime_capi): add missing docs The mun_runtime_capi crate now warns when there are missing docs. --- crates/mun_runtime_capi/src/error.rs | 6 +++++ crates/mun_runtime_capi/src/hub.rs | 11 +++++++++ crates/mun_runtime_capi/src/lib.rs | 34 ++++++++++++++++++++++++++-- 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/crates/mun_runtime_capi/src/error.rs b/crates/mun_runtime_capi/src/error.rs index 30423d598..805cd3278 100644 --- a/crates/mun_runtime_capi/src/error.rs +++ b/crates/mun_runtime_capi/src/error.rs @@ -1,3 +1,5 @@ +//! Exposes error reporting using the C ABI. + use std::ffi::CString; use std::hash::Hash; use std::os::raw::c_char; @@ -6,6 +8,7 @@ use std::ptr; use crate::hub::HUB; use crate::{Token, TypedHandle}; +/// A C-style handle to an error. #[repr(C)] #[derive(Clone, Copy, Debug, Default, Hash, Eq, PartialEq)] pub struct ErrorHandle(Token); @@ -20,12 +23,15 @@ impl TypedHandle for ErrorHandle { } } +/// Destructs the error corresponding to `error_handle`. #[no_mangle] pub extern "C" fn mun_error_destroy(error_handle: ErrorHandle) { // If an error exists, destroy it let _error = HUB.errors.unregister(error_handle); } +/// Retrieves the error message corresponding to `error_handle`. If the `error_handle` exists, a +/// valid `char` pointer is returned, otherwise a null-pointer is returned. #[no_mangle] pub extern "C" fn mun_error_message(error_handle: ErrorHandle) -> *const c_char { let errors = HUB.errors.get_data(); diff --git a/crates/mun_runtime_capi/src/hub.rs b/crates/mun_runtime_capi/src/hub.rs index 1bebfe043..0645d7655 100644 --- a/crates/mun_runtime_capi/src/hub.rs +++ b/crates/mun_runtime_capi/src/hub.rs @@ -1,3 +1,6 @@ +//! A statically-allocated, concurrent data structure for storage of Rust objects that are utilized +//! through Mun Runtime C API calls. + use std::collections::HashMap; use std::hash::Hash; use std::sync::Arc; @@ -18,6 +21,7 @@ fn generate_handle() -> H { } } +/// A concurrent registry for uniquely indexed values. pub struct Registry { data: RwLock>, } @@ -26,6 +30,7 @@ impl Registry where H: Copy + Eq + Hash + TypedHandle, { + /// Inserts `value` and returns a unique handle to it. pub fn register(&self, value: T) -> H { let handle = { let data = self.data.read(); @@ -41,10 +46,12 @@ where handle } + /// Removes and returns the value corresponding to `handle`, if it is found. pub fn unregister(&self, handle: H) -> Option { self.data.write().remove(&handle) } + /// Retrieves the inner data pub fn get_data(&self) -> RwLockReadGuard> { self.data.read() } @@ -61,11 +68,15 @@ where } } +/// Concurrent data structure for storage of Rust objects that are utilized through Mun Runtime +/// C API calls. #[derive(Default)] pub struct Hub { + /// Error registry pub errors: Arc>>, } lazy_static! { + /// Storage for Rust objects that are utilized through Mun Runtime C API calls. pub static ref HUB: Hub = Hub::default(); } diff --git a/crates/mun_runtime_capi/src/lib.rs b/crates/mun_runtime_capi/src/lib.rs index af273d5c4..8e7545985 100644 --- a/crates/mun_runtime_capi/src/lib.rs +++ b/crates/mun_runtime_capi/src/lib.rs @@ -1,5 +1,11 @@ -mod error; -mod hub; +//! The Mun Runtime C API +//! +//! The Mun Runtime C API exposes runtime functionality using the C ABI. This can be used to +//! integrate the Mun Runtime into other languages that allow interoperability with C. +#![warn(missing_docs)] + +pub mod error; +pub mod hub; use std::ffi::{c_void, CStr}; use std::os::raw::c_char; @@ -12,14 +18,27 @@ use mun_runtime::{MunRuntime, RuntimeBuilder}; pub(crate) type Token = usize; +/// A type to uniquely index typed collections. pub trait TypedHandle { + /// Constructs a new `TypedHandle`. fn new(token: Token) -> Self; + /// Retrieves the handle's token. fn token(&self) -> Token; } +/// A C-style handle to a runtime. #[repr(C)] pub struct RuntimeHandle(*mut c_void); +/// Constructs a new runtime that loads the library at `library_path` and its dependencies. If +/// successful, the runtime `handle` is set, otherwise a non-zero error handle is returned. +/// +/// If a non-zero error handle is returned, it must be manually destructed using +/// [`mun_error_destroy`]. +/// +/// The runtime must be manually destructed using [`mun_runtime_destroy`]. +/// +/// TOOD: expose interval at which the runtime's file watcher operates. #[no_mangle] pub unsafe extern "C" fn mun_runtime_create( library_path: *const c_char, @@ -58,6 +77,7 @@ pub unsafe extern "C" fn mun_runtime_create( ErrorHandle::default() } +/// Destructs the runtime corresponding to `handle`. #[no_mangle] pub extern "C" fn mun_runtime_destroy(handle: RuntimeHandle) { if !handle.0.is_null() { @@ -65,6 +85,11 @@ pub extern "C" fn mun_runtime_destroy(handle: RuntimeHandle) { } } +/// Retrieves the [`FunctionInfo`] for `fn_name` from the runtime corresponding to `handle`. If +/// successful, `has_fn_info` and `fn_info` are set, otherwise a non-zero error handle is returned. +/// +/// If a non-zero error handle is returned, it must be manually destructed using +/// [`mun_error_destroy`]. #[no_mangle] pub unsafe extern "C" fn mun_runtime_get_function_info( handle: RuntimeHandle, @@ -119,6 +144,11 @@ pub unsafe extern "C" fn mun_runtime_get_function_info( ErrorHandle::default() } +/// Updates the runtime corresponding to `handle`. If successful, `updated` is set, otherwise a +/// non-zero error handle is returned. +/// +/// If a non-zero error handle is returned, it must be manually destructed using +/// [`mun_error_destroy`]. #[no_mangle] pub unsafe extern "C" fn mun_runtime_update( handle: RuntimeHandle, From fc1cc51c4e972f5bf2ab1b8f42f22d9751e12bd2 Mon Sep 17 00:00:00 2001 From: Wodann Date: Thu, 31 Oct 2019 16:41:58 +0100 Subject: [PATCH 06/11] refactor: rename `MunRuntime` struct to `Runtime` --- crates/mun/src/main.rs | 4 +- crates/mun_runtime/src/lib.rs | 18 ++++----- crates/mun_runtime/src/macros.rs | 36 +++++++++--------- crates/mun_runtime/src/test.rs | 60 +++++++++++++++--------------- crates/mun_runtime_capi/src/lib.rs | 6 +-- 5 files changed, 61 insertions(+), 63 deletions(-) diff --git a/crates/mun/src/main.rs b/crates/mun/src/main.rs index b90388222..197aeae3e 100644 --- a/crates/mun/src/main.rs +++ b/crates/mun/src/main.rs @@ -5,7 +5,7 @@ use std::time::Duration; use clap::{App, AppSettings, Arg, ArgMatches, SubCommand}; use mun_compiler::PathOrInline; -use mun_runtime::{invoke_fn, MunRuntime, RuntimeBuilder}; +use mun_runtime::{invoke_fn, Runtime, RuntimeBuilder}; fn main() -> Result<(), failure::Error> { let matches = App::new("mun") @@ -109,7 +109,7 @@ fn compiler_options(matches: &ArgMatches) -> Result Result { +fn runtime(matches: &ArgMatches) -> Result { let mut builder = RuntimeBuilder::new( matches.value_of("LIBRARY").unwrap(), // Safe because its a required arg ); diff --git a/crates/mun_runtime/src/lib.rs b/crates/mun_runtime/src/lib.rs index 56281f25e..0bcc540cd 100644 --- a/crates/mun_runtime/src/lib.rs +++ b/crates/mun_runtime/src/lib.rs @@ -43,8 +43,8 @@ impl RuntimeBuilder { self } - pub fn spawn(self) -> Result { - MunRuntime::new(self.options) + pub fn spawn(self) -> Result { + Runtime::new(self.options) } } @@ -72,23 +72,23 @@ impl DispatchTable { } } -/// A runtime for the Mun scripting language. -pub struct MunRuntime { +/// A runtime for the Mun language. +pub struct Runtime { assemblies: HashMap, dispatch_table: DispatchTable, watcher: RecommendedWatcher, watcher_rx: Receiver, } -impl MunRuntime { - /// Constructs a new `MunRuntime` that loads the library at `library_path` and its - /// dependencies. The `MunRuntime` contains a file watcher that is triggered with an interval +impl Runtime { + /// Constructs a new `Runtime` that loads the library at `library_path` and its + /// dependencies. The `Runtime` contains a file watcher that is triggered with an interval /// of `dur`. - pub fn new(options: RuntimeOptions) -> Result { + pub fn new(options: RuntimeOptions) -> Result { let (tx, rx) = channel(); let watcher: RecommendedWatcher = Watcher::new(tx, options.delay)?; - let mut runtime = MunRuntime { + let mut runtime = Runtime { assemblies: HashMap::new(), dispatch_table: DispatchTable::default(), watcher, diff --git a/crates/mun_runtime/src/macros.rs b/crates/mun_runtime/src/macros.rs index c3ea35b86..bb2a65584 100644 --- a/crates/mun_runtime/src/macros.rs +++ b/crates/mun_runtime/src/macros.rs @@ -8,7 +8,7 @@ macro_rules! invoke_fn_impl { /// the function invocation using the `Retriable` trait. pub struct $ErrName<'r, 's, $($T: Reflection,)* Output:Reflection> { msg: String, - runtime: &'r mut MunRuntime, + runtime: &'r mut Runtime, function_name: &'s str, $($Arg: $T,)* output: core::marker::PhantomData, @@ -35,7 +35,7 @@ macro_rules! invoke_fn_impl { impl<'r, 's, $($T: Reflection,)* Output: Reflection> $ErrName<'r, 's, $($T,)* Output> { /// Constructs a new invocation error. #[allow(clippy::too_many_arguments)] - pub fn new(err_msg: String, runtime: &'r mut MunRuntime, function_name: &'s str, $($Arg: $T),*) -> Self { + pub fn new(err_msg: String, runtime: &'r mut Runtime, function_name: &'s str, $($Arg: $T),*) -> Self { Self { msg: err_msg, runtime, @@ -57,7 +57,7 @@ macro_rules! invoke_fn_impl { while !err.runtime.update() { // Wait until there has been an update that might fix the error } - $crate::MunRuntime::$FnName(err.runtime, err.function_name, $(err.$Arg,)*) + $crate::Runtime::$FnName(err.runtime, err.function_name, $(err.$Arg,)*) } } } @@ -72,7 +72,7 @@ macro_rules! invoke_fn_impl { } } - impl MunRuntime { + impl Runtime { /// Invokes the method `method_name` with arguments `args`, in the library compiled /// based on the manifest at `manifest_path`. /// @@ -80,7 +80,7 @@ macro_rules! invoke_fn_impl { /// runtime continues looping until the cause of the error has been resolved. #[allow(clippy::too_many_arguments)] pub fn $FnName<'r, 's, $($T: Reflection,)* Output: Reflection>( - runtime: &'r mut MunRuntime, + runtime: &'r mut Runtime, function_name: &'s str, $($Arg: $T,)* ) -> core::result::Result> { @@ -102,37 +102,37 @@ macro_rules! invoke_fn_impl { #[macro_export] macro_rules! invoke_fn { ($Runtime:expr, $FnName:expr) => { - $crate::MunRuntime::invoke_fn0(&mut $Runtime, $FnName) + $crate::Runtime::invoke_fn0(&mut $Runtime, $FnName) }; ($Runtime:expr, $FnName:expr, $A:expr) => { - $crate::MunRuntime::invoke_fn1(&mut $Runtime, $FnName, $A) + $crate::Runtime::invoke_fn1(&mut $Runtime, $FnName, $A) }; ($Runtime:expr, $FnName:expr, $A:expr, $B:expr) => { - $crate::MunRuntime::invoke_fn2(&mut $Runtime, $FnName, $A, $B) + $crate::Runtime::invoke_fn2(&mut $Runtime, $FnName, $A, $B) }; ($Runtime:expr, $FnName:expr, $A:expr, $B:expr, $C:expr) => { - $crate::MunRuntime::invoke_fn3(&mut $Runtime, $FnName, $A, $B, $C) + $crate::Runtime::invoke_fn3(&mut $Runtime, $FnName, $A, $B, $C) }; ($Runtime:expr, $FnName:expr, $A:expr, $B:expr, $C:expr, $D:expr) => { - $crate::MunRuntime::invoke_fn4(&mut $Runtime, $FnName, $A, $B, $C, $D) + $crate::Runtime::invoke_fn4(&mut $Runtime, $FnName, $A, $B, $C, $D) }; ($Runtime:expr, $FnName:expr, $A:expr, $B:expr, $C:expr, $D:expr, $E:expr) => { - $crate::MunRuntime::invoke_fn5(&mut $Runtime, $FnName, $A, $B, $C, $D, $E) + $crate::Runtime::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) => { - $crate::MunRuntime::invoke_fn6(&mut $Runtime, $FnName, $A, $B, $C, $D, $E, $F) + $crate::Runtime::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) => { - $crate::MunRuntime::invoke_fn7(&mut $Runtime, $FnName, $A, $B, $C, $D, $E, $F, $G) + $crate::Runtime::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) => { - $crate::MunRuntime::invoke_fn8(&mut $Runtime, $FnName, $A, $B, $C, $D, $E, $F, $G, $H) + $crate::Runtime::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) => { - $crate::MunRuntime::invoke_fn9(&mut $Runtime, $FnName, $A, $B, $C, $D, $E, $F, $G, $H, $I) + $crate::Runtime::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) => { - $crate::MunRuntime::invoke_fn10( + $crate::Runtime::invoke_fn10( &mut $Runtime, $FnName, $A, @@ -148,12 +148,12 @@ macro_rules! invoke_fn { ) }; ($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) => { - $crate::MunRuntime::invoke_fn11( + $crate::Runtime::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) => { - $crate::MunRuntime::invoke_fn12( + $crate::Runtime::invoke_fn12( $Runtime, $FnName, $A, $B, $C, $D, $E, $F, $G, $H, $I, $J, $K, $L, ) }; diff --git a/crates/mun_runtime/src/test.rs b/crates/mun_runtime/src/test.rs index 6388d8a9f..c748193bf 100644 --- a/crates/mun_runtime/src/test.rs +++ b/crates/mun_runtime/src/test.rs @@ -1,4 +1,4 @@ -use crate::{MunRuntime, RuntimeBuilder}; +use crate::{Runtime, RuntimeBuilder}; use mun_compiler::CompilerOptions; use std::path::PathBuf; @@ -10,7 +10,7 @@ struct CompileResult { impl CompileResult { /// Construct a runtime from the compilation result that can be used to execute the compiled /// files. - pub fn new_runtime(&self) -> MunRuntime { + pub fn new_runtime(&self) -> Runtime { RuntimeBuilder::new(&self.result).spawn().unwrap() } } @@ -107,102 +107,100 @@ fn booleans() { ); let mut runtime = compile_result.new_runtime(); assert_eq!( - MunRuntime::invoke_fn2::(&mut runtime, "equal", 52, 764).unwrap(), + Runtime::invoke_fn2::(&mut runtime, "equal", 52, 764).unwrap(), false ); assert_eq!( - MunRuntime::invoke_fn2::(&mut runtime, "equal", 64, 64).unwrap(), + Runtime::invoke_fn2::(&mut runtime, "equal", 64, 64).unwrap(), true ); assert_eq!( - MunRuntime::invoke_fn2::(&mut runtime, "equalf", 123.0, 123.0).unwrap(), + Runtime::invoke_fn2::(&mut runtime, "equalf", 123.0, 123.0).unwrap(), true ); assert_eq!( - MunRuntime::invoke_fn2::(&mut runtime, "equalf", 123.0, 234.0).unwrap(), + Runtime::invoke_fn2::(&mut runtime, "equalf", 123.0, 234.0).unwrap(), false ); assert_eq!( - MunRuntime::invoke_fn2::(&mut runtime, "not_equal", 52, 764).unwrap(), + Runtime::invoke_fn2::(&mut runtime, "not_equal", 52, 764).unwrap(), true ); assert_eq!( - MunRuntime::invoke_fn2::(&mut runtime, "not_equal", 64, 64).unwrap(), + Runtime::invoke_fn2::(&mut runtime, "not_equal", 64, 64).unwrap(), false ); assert_eq!( - MunRuntime::invoke_fn2::(&mut runtime, "not_equalf", 123.0, 123.0).unwrap(), + Runtime::invoke_fn2::(&mut runtime, "not_equalf", 123.0, 123.0).unwrap(), false ); assert_eq!( - MunRuntime::invoke_fn2::(&mut runtime, "not_equalf", 123.0, 234.0).unwrap(), + Runtime::invoke_fn2::(&mut runtime, "not_equalf", 123.0, 234.0).unwrap(), true ); assert_eq!( - MunRuntime::invoke_fn2::(&mut runtime, "less", 52, 764).unwrap(), + Runtime::invoke_fn2::(&mut runtime, "less", 52, 764).unwrap(), true ); assert_eq!( - MunRuntime::invoke_fn2::(&mut runtime, "less", 64, 64).unwrap(), + Runtime::invoke_fn2::(&mut runtime, "less", 64, 64).unwrap(), false ); assert_eq!( - MunRuntime::invoke_fn2::(&mut runtime, "lessf", 123.0, 123.0).unwrap(), + Runtime::invoke_fn2::(&mut runtime, "lessf", 123.0, 123.0).unwrap(), false ); assert_eq!( - MunRuntime::invoke_fn2::(&mut runtime, "lessf", 123.0, 234.0).unwrap(), + Runtime::invoke_fn2::(&mut runtime, "lessf", 123.0, 234.0).unwrap(), true ); assert_eq!( - MunRuntime::invoke_fn2::(&mut runtime, "greater", 52, 764).unwrap(), + Runtime::invoke_fn2::(&mut runtime, "greater", 52, 764).unwrap(), false ); assert_eq!( - MunRuntime::invoke_fn2::(&mut runtime, "greater", 64, 64).unwrap(), + Runtime::invoke_fn2::(&mut runtime, "greater", 64, 64).unwrap(), false ); assert_eq!( - MunRuntime::invoke_fn2::(&mut runtime, "greaterf", 123.0, 123.0).unwrap(), + Runtime::invoke_fn2::(&mut runtime, "greaterf", 123.0, 123.0).unwrap(), false ); assert_eq!( - MunRuntime::invoke_fn2::(&mut runtime, "greaterf", 123.0, 234.0).unwrap(), + Runtime::invoke_fn2::(&mut runtime, "greaterf", 123.0, 234.0).unwrap(), false ); assert_eq!( - MunRuntime::invoke_fn2::(&mut runtime, "less_equal", 52, 764).unwrap(), + Runtime::invoke_fn2::(&mut runtime, "less_equal", 52, 764).unwrap(), true ); assert_eq!( - MunRuntime::invoke_fn2::(&mut runtime, "less_equal", 64, 64).unwrap(), + Runtime::invoke_fn2::(&mut runtime, "less_equal", 64, 64).unwrap(), true ); assert_eq!( - MunRuntime::invoke_fn2::(&mut runtime, "lessf_equal", 123.0, 123.0) - .unwrap(), + Runtime::invoke_fn2::(&mut runtime, "lessf_equal", 123.0, 123.0).unwrap(), true ); assert_eq!( - MunRuntime::invoke_fn2::(&mut runtime, "lessf_equal", 123.0, 234.0) - .unwrap(), + Runtime::invoke_fn2::(&mut runtime, "lessf_equal", 123.0, 234.0).unwrap(), true ); assert_eq!( - MunRuntime::invoke_fn2::(&mut runtime, "greater_equal", 52, 764).unwrap(), + Runtime::invoke_fn2::(&mut runtime, "greater_equal", 52, 764).unwrap(), false ); assert_eq!( - MunRuntime::invoke_fn2::(&mut runtime, "greater_equal", 64, 64).unwrap(), + Runtime::invoke_fn2::(&mut runtime, "greater_equal", 64, 64).unwrap(), true ); assert_eq!( - MunRuntime::invoke_fn2::(&mut runtime, "greaterf_equal", 123.0, 123.0) + Runtime::invoke_fn2::(&mut runtime, "greaterf_equal", 123.0, 123.0) .unwrap(), true ); assert_eq!( - MunRuntime::invoke_fn2::(&mut runtime, "greaterf_equal", 123.0, 234.0) + Runtime::invoke_fn2::(&mut runtime, "greaterf_equal", 123.0, 234.0) .unwrap(), false ); @@ -223,15 +221,15 @@ fn fibonacci() { ); let mut runtime = compile_result.new_runtime(); assert_eq!( - MunRuntime::invoke_fn1::(&mut runtime, "fibonacci", 5).unwrap(), + Runtime::invoke_fn1::(&mut runtime, "fibonacci", 5).unwrap(), 5 ); assert_eq!( - MunRuntime::invoke_fn1::(&mut runtime, "fibonacci", 11).unwrap(), + Runtime::invoke_fn1::(&mut runtime, "fibonacci", 11).unwrap(), 89 ); assert_eq!( - MunRuntime::invoke_fn1::(&mut runtime, "fibonacci", 16).unwrap(), + Runtime::invoke_fn1::(&mut runtime, "fibonacci", 16).unwrap(), 987 ); } diff --git a/crates/mun_runtime_capi/src/lib.rs b/crates/mun_runtime_capi/src/lib.rs index 8e7545985..9fc29bc74 100644 --- a/crates/mun_runtime_capi/src/lib.rs +++ b/crates/mun_runtime_capi/src/lib.rs @@ -14,7 +14,7 @@ use crate::error::ErrorHandle; use crate::hub::HUB; use failure::err_msg; use mun_abi::FunctionInfo; -use mun_runtime::{MunRuntime, RuntimeBuilder}; +use mun_runtime::{Runtime, RuntimeBuilder}; pub(crate) type Token = usize; @@ -97,7 +97,7 @@ pub unsafe extern "C" fn mun_runtime_get_function_info( has_fn_info: *mut bool, fn_info: *mut FunctionInfo, ) -> ErrorHandle { - let runtime = match (handle.0 as *mut MunRuntime).as_ref() { + let runtime = match (handle.0 as *mut Runtime).as_ref() { Some(runtime) => runtime, None => { return HUB.errors.register(Box::new(err_msg( @@ -154,7 +154,7 @@ pub unsafe extern "C" fn mun_runtime_update( handle: RuntimeHandle, updated: *mut bool, ) -> ErrorHandle { - let runtime = match (handle.0 as *mut MunRuntime).as_mut() { + let runtime = match (handle.0 as *mut Runtime).as_mut() { Some(runtime) => runtime, None => { return HUB.errors.register(Box::new(err_msg( From 53878d56126d142a8a008dc76b92637c6dd60adc Mon Sep 17 00:00:00 2001 From: Wodann Date: Thu, 31 Oct 2019 17:24:38 +0100 Subject: [PATCH 07/11] doc(runtime): add missing docs The mun_runtime crate now warns when there are missing docs. --- crates/mun_runtime/src/lib.rs | 17 ++++++++++++++++- crates/mun_runtime/src/macros.rs | 8 ++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/crates/mun_runtime/src/lib.rs b/crates/mun_runtime/src/lib.rs index 0bcc540cd..4979dcc7b 100644 --- a/crates/mun_runtime/src/lib.rs +++ b/crates/mun_runtime/src/lib.rs @@ -1,3 +1,9 @@ +//! The Mun Runtime +//! +//! The Mun Runtime provides functionality for automatically hot reloading Mun C ABI +//! compliant shared libraries. +#![warn(missing_docs)] + mod assembly; #[macro_use] mod macros; @@ -17,18 +23,22 @@ use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher}; pub use crate::assembly::Assembly; +/// Options for the construction of a [`Runtime`]. #[derive(Clone, Debug)] pub struct RuntimeOptions { + /// Path to the entry point library pub library_path: PathBuf, + /// Delay during which filesystem events are collected, deduplicated, and after which emitted. pub delay: Duration, } -/// A builder for the runtime. +/// A builder for the [`Runtime`]. pub struct RuntimeBuilder { options: RuntimeOptions, } impl RuntimeBuilder { + /// Constructs a new `RuntimeBuilder` for the shared library at `library_path`. pub fn new>(library_path: P) -> Self { Self { options: RuntimeOptions { @@ -38,11 +48,13 @@ impl RuntimeBuilder { } } + /// Sets the `delay`. pub fn set_delay(&mut self, delay: Duration) -> &mut Self { self.options.delay = delay; self } + /// Spawns a [`Runtime`] with the builder's options. pub fn spawn(self) -> Result { Runtime::new(self.options) } @@ -55,6 +67,7 @@ pub struct DispatchTable { } impl DispatchTable { + /// Retrieves the [`FunctionInfo`] corresponding to `fn_path`, if it exists. pub fn get(&self, fn_path: &str) -> Option<&FunctionInfo> { self.functions.get(fn_path) } @@ -67,6 +80,7 @@ impl DispatchTable { self.functions.insert(fn_path.to_string(), fn_info) } + /// Removes and returns the `fn_info` corresponding to `fn_path`, if it exists. pub fn remove(&mut self, fn_path: &str) -> Option { self.functions.remove(fn_path) } @@ -153,6 +167,7 @@ impl Runtime { /// Extends a result object with functions that allow retrying of an action. pub trait RetryResultExt: Sized { + /// Output type on success type Output; /// Retries an action, resulting in a potentially mutated version of itself. diff --git a/crates/mun_runtime/src/macros.rs b/crates/mun_runtime/src/macros.rs index bb2a65584..77705c1aa 100644 --- a/crates/mun_runtime/src/macros.rs +++ b/crates/mun_runtime/src/macros.rs @@ -99,6 +99,14 @@ macro_rules! invoke_fn_impl { } } +/// Invokes a runtime function and returns a [`Result`] that implements the [`RetryResultExt`] +/// trait. +/// +/// The first argument `invoke_fn` receives is a `Runtime` and the second argument is a function +/// string. This must be a `&str`. +/// +/// Additional parameters passed to `invoke_fn` are the arguments of the function in the order +/// given. #[macro_export] macro_rules! invoke_fn { ($Runtime:expr, $FnName:expr) => { From 771539e3dccbde380c8875d97d54ae2c1313e328 Mon Sep 17 00:00:00 2001 From: Wodann Date: Thu, 31 Oct 2019 21:41:51 +0100 Subject: [PATCH 08/11] refactor(runtime_capi): merge C API and C++ bindings into ffi folder --- .gitmodules | 9 +++------ crates/mun_runtime_capi/build.rs | 6 +++--- crates/mun_runtime_capi/c | 1 - crates/mun_runtime_capi/cpp | 1 - crates/mun_runtime_capi/ffi | 1 + 5 files changed, 7 insertions(+), 11 deletions(-) delete mode 160000 crates/mun_runtime_capi/c delete mode 160000 crates/mun_runtime_capi/cpp create mode 160000 crates/mun_runtime_capi/ffi diff --git a/.gitmodules b/.gitmodules index 2218aef14..c33292cd3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +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 -[submodule "crates/mun_runtime_capi/cpp"] - path = crates/mun_runtime_capi/cpp - url = ../../mun-lang/runtime-cpp.git +[submodule "crates/mun_runtime_capi/ffi"] + path = crates/mun_runtime_capi/ffi + url = ../../mun-lang/runtime-ffi.git diff --git a/crates/mun_runtime_capi/build.rs b/crates/mun_runtime_capi/build.rs index b9af05b20..d3e33b7b7 100644 --- a/crates/mun_runtime_capi/build.rs +++ b/crates/mun_runtime_capi/build.rs @@ -5,7 +5,7 @@ use cbindgen; fn main() { let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); - let bindings = cbindgen::generate(crate_dir).expect("Unable to generate Mun Runtime bindings."); - bindings.write_to_file("c/include/mun/runtime.h"); - bindings.write_to_file("cpp/include/mun/runtime_capi.h"); + cbindgen::generate(crate_dir) + .expect("Unable to generate Mun Runtime bindings.") + .write_to_file("ffi/include/mun/runtime_capi.h"); } diff --git a/crates/mun_runtime_capi/c b/crates/mun_runtime_capi/c deleted file mode 160000 index 86c314e1b..000000000 --- a/crates/mun_runtime_capi/c +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 86c314e1b1ecbdce76f52cd839e841cc6f91c5de diff --git a/crates/mun_runtime_capi/cpp b/crates/mun_runtime_capi/cpp deleted file mode 160000 index 7ee823c3c..000000000 --- a/crates/mun_runtime_capi/cpp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7ee823c3c09f6bba84981704f27df606e9458c79 diff --git a/crates/mun_runtime_capi/ffi b/crates/mun_runtime_capi/ffi new file mode 160000 index 000000000..7473aa4a7 --- /dev/null +++ b/crates/mun_runtime_capi/ffi @@ -0,0 +1 @@ +Subproject commit 7473aa4a7790acfdeb337462f30c6882ad0e0415 From b61098d16d9c15d0c1eb386cc229075c87625639 Mon Sep 17 00:00:00 2001 From: Wodann Date: Fri, 1 Nov 2019 11:21:35 +0100 Subject: [PATCH 09/11] fix: prevent bindgen making type aliases of native C types --- crates/mun_abi/build.rs | 7 +++++++ crates/mun_abi/c | 2 +- crates/mun_abi/src/autogen.rs | 27 +++++++++++++++++---------- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/crates/mun_abi/build.rs b/crates/mun_abi/build.rs index f002e1c7f..f40b9c306 100644 --- a/crates/mun_abi/build.rs +++ b/crates/mun_abi/build.rs @@ -34,7 +34,14 @@ fn main() { .header("c/include/mun_abi.h") .whitelist_type("Mun.*") .blacklist_type("MunPrivacy.*") + // Remove type aliasing on Linux + .blacklist_type("__uint8_t") + .blacklist_type("__uint16_t") + .blacklist_type("__uint32_t") .parse_callbacks(Box::new(RemoveVendorName)) + // FIXME: Prevent double derivation of Copy and Debug attributes on Windows + .derive_copy(false) + .derive_debug(false) .raw_line("#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]") .raw_line("use crate::Privacy;") .generate() diff --git a/crates/mun_abi/c b/crates/mun_abi/c index 709318f7b..5db0081b8 160000 --- a/crates/mun_abi/c +++ b/crates/mun_abi/c @@ -1 +1 @@ -Subproject commit 709318f7bc8eaca2e920589b6f03c9ac2a95b4fa +Subproject commit 5db0081b833c0b2b4d1a82206d56e55278c3af94 diff --git a/crates/mun_abi/src/autogen.rs b/crates/mun_abi/src/autogen.rs index c44dfb0fb..d673ae8c1 100644 --- a/crates/mun_abi/src/autogen.rs +++ b/crates/mun_abi/src/autogen.rs @@ -7,9 +7,9 @@ use crate::Privacy; #[doc = ""] #[doc = " GUIDs are generated by taking the MD5 hash of a type's name."] #[doc = ""] -#[doc = "
"] +#[doc = "
"] #[repr(C)] -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] pub struct Guid { #[doc = " 16-byte MD5 hash"] pub b: [u8; 16usize], @@ -35,8 +35,10 @@ fn bindgen_test_layout_Guid() { #[doc = " Represents the type declaration for a value type."] #[doc = ""] #[doc = " TODO: add support for structs, polymorphism, enumerations, type parameters, generic type definitions, and constructed generic types."] +#[doc = ""] +#[doc = "
"] #[repr(C)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug)] pub struct TypeInfo { #[doc = " Type GUID"] pub guid: Guid, @@ -78,9 +80,9 @@ fn bindgen_test_layout_TypeInfo() { } #[doc = " Represents a function signature."] #[doc = ""] -#[doc = "
"] +#[doc = "
"] #[repr(C)] -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct FunctionSignature { #[doc = " Function name"] pub name: *const ::std::os::raw::c_char, @@ -160,9 +162,9 @@ fn bindgen_test_layout_FunctionSignature() { #[doc = ""] #[doc = " `fn_ptr` can be used to call the declared function."] #[doc = ""] -#[doc = "
"] +#[doc = "
"] #[repr(C)] -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct FunctionInfo { #[doc = " Function signature"] pub signature: FunctionSignature, @@ -203,8 +205,10 @@ fn bindgen_test_layout_FunctionInfo() { ); } #[doc = " Represents a module declaration."] +#[doc = ""] +#[doc = "
"] #[repr(C)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug)] pub struct ModuleInfo { #[doc = " Module path"] pub path: *const ::std::os::raw::c_char, @@ -260,8 +264,9 @@ fn bindgen_test_layout_ModuleInfo() { #[doc = ""] #[doc = " Function signatures and pointers are stored separately for cache efficiency."] #[doc = ""] +#[doc = "
"] #[repr(C)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug)] pub struct DispatchTable { #[doc = " Function signatures"] pub signatures: *const FunctionSignature, @@ -314,8 +319,10 @@ fn bindgen_test_layout_DispatchTable() { ); } #[doc = " Represents an assembly declaration."] +#[doc = ""] +#[doc = "
"] #[repr(C)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug)] pub struct AssemblyInfo { #[doc = " Symbols of the top-level module"] pub symbols: ModuleInfo, From e4dd123663f61cb93cfc8d1a89b13b7f8a98d7d2 Mon Sep 17 00:00:00 2001 From: Wodann Date: Tue, 5 Nov 2019 16:57:06 +0100 Subject: [PATCH 10/11] feat(runtime_capi): update FFI bindings and binaries --- crates/mun_runtime_capi/ffi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/mun_runtime_capi/ffi b/crates/mun_runtime_capi/ffi index 7473aa4a7..830bf08ff 160000 --- a/crates/mun_runtime_capi/ffi +++ b/crates/mun_runtime_capi/ffi @@ -1 +1 @@ -Subproject commit 7473aa4a7790acfdeb337462f30c6882ad0e0415 +Subproject commit 830bf08ff806a53d689b25a9dc803cbf0c84c096 From 864ff111f2da154c2f73b833e1917aeb79ce25d8 Mon Sep 17 00:00:00 2001 From: Wodann Date: Sat, 2 Nov 2019 20:35:20 +0100 Subject: [PATCH 11/11] feat(runtime_example): add example of hot reloading in the Mun Runtime --- crates/mun_runtime/examples/hot_reloading.rs | 22 +++++++++++++++++++ .../examples/resources/fibonacci.mun | 11 ++++++++++ 2 files changed, 33 insertions(+) create mode 100644 crates/mun_runtime/examples/hot_reloading.rs create mode 100644 crates/mun_runtime/examples/resources/fibonacci.mun diff --git a/crates/mun_runtime/examples/hot_reloading.rs b/crates/mun_runtime/examples/hot_reloading.rs new file mode 100644 index 000000000..7f544d14e --- /dev/null +++ b/crates/mun_runtime/examples/hot_reloading.rs @@ -0,0 +1,22 @@ +use mun_runtime::{invoke_fn, RetryResultExt, RuntimeBuilder}; +use std::env; + +// How to run? +// 1. On the CLI, navigate to the `crates/mun_runtime/examples` directory. +// 2. Run the compiler daemon from the CLI: `/path/to/mun build resources/fibonacci.mun --watch` +// 3. Run the application from the CLI: cargo run --example hot_reloading -- fibonacci.dll +fn main() { + let lib_dir = env::args().nth(1).expect("Expected path to a Mun library."); + println!("lib: {}", lib_dir); + + let mut runtime = RuntimeBuilder::new(lib_dir) + .spawn() + .expect("Failed to spawn Runtime"); + + loop { + let n: i64 = invoke_fn!(runtime, "nth").wait(); + let result: i64 = invoke_fn!(runtime, "fibonacci", n).wait(); + println!("fibonacci({}) = {}", n, result); + runtime.update(); + } +} diff --git a/crates/mun_runtime/examples/resources/fibonacci.mun b/crates/mun_runtime/examples/resources/fibonacci.mun new file mode 100644 index 000000000..4645748e7 --- /dev/null +++ b/crates/mun_runtime/examples/resources/fibonacci.mun @@ -0,0 +1,11 @@ +fn nth(): int { + 3 +} + +fn fibonacci(n:int):int { + if n <= 1 { + n + } else { + fibonacci(n-1) + fibonacci(n-2) + } +}