diff --git a/crates/mun/src/main.rs b/crates/mun/src/main.rs index c2b14b660..50d44ca3a 100644 --- a/crates/mun/src/main.rs +++ b/crates/mun/src/main.rs @@ -169,14 +169,16 @@ fn compiler_options(matches: &ArgMatches) -> Result Result { - let mut builder = RuntimeBuilder::new( + let builder = RuntimeBuilder::new( matches.value_of("LIBRARY").unwrap(), // Safe because its a required arg ); - if let Some(delay) = matches.value_of("delay") { + let builder = if let Some(delay) = matches.value_of("delay") { let delay: u64 = delay.parse()?; - builder.set_delay(Duration::from_millis(delay)); - } + builder.set_delay(Duration::from_millis(delay)) + } else { + builder + }; builder.spawn() } diff --git a/crates/mun_abi/Cargo.toml b/crates/mun_abi/Cargo.toml index 3e7363012..94c426629 100644 --- a/crates/mun_abi/Cargo.toml +++ b/crates/mun_abi/Cargo.toml @@ -7,3 +7,8 @@ homepage = "https://mun-lang.org" repository = "https://github.com/mun-lang/mun" license = "MIT OR Apache-2.0" description = "Rust wrapper for the Mun ABI" + +[dependencies] +md5 = "0.7.0" +once_cell = "1.3.1" +parking_lot = "0.10" diff --git a/crates/mun_runtime/src/function.rs b/crates/mun_abi/src/function_info.rs similarity index 72% rename from crates/mun_runtime/src/function.rs rename to crates/mun_abi/src/function_info.rs index 098474713..79d5b49b8 100644 --- a/crates/mun_runtime/src/function.rs +++ b/crates/mun_abi/src/function_info.rs @@ -1,23 +1,23 @@ -use std::ffi::CString; -use std::ptr; - -use crate::type_info::HasStaticTypeInfo; +use crate::{FunctionInfo, FunctionSignature, HasStaticTypeInfo, Privacy, TypeInfo}; +use std::{ffi::CString, ptr}; +/// Owned storage for C-style `FunctionInfo`. pub struct FunctionInfoStorage { _name: CString, - _type_infos: Vec<&'static abi::TypeInfo>, + _type_infos: Vec<&'static TypeInfo>, } impl FunctionInfoStorage { + /// Constructs a new `FunctionInfo`, the data of which is stored in a `FunctionInfoStorage`. pub fn new_function( name: &str, - args: &[&'static abi::TypeInfo], - ret: Option<&'static abi::TypeInfo>, - privacy: abi::Privacy, + args: &[&'static TypeInfo], + ret: Option<&'static TypeInfo>, + privacy: Privacy, fn_ptr: *const std::ffi::c_void, - ) -> (abi::FunctionInfo, FunctionInfoStorage) { + ) -> (FunctionInfo, FunctionInfoStorage) { let name = CString::new(name).unwrap(); - let type_infos: Vec<&'static abi::TypeInfo> = args.iter().copied().collect(); + let type_infos: Vec<&'static TypeInfo> = args.iter().copied().collect(); let num_arg_types = type_infos.len() as u16; let return_type = if let Some(ty) = ret { @@ -26,8 +26,8 @@ impl FunctionInfoStorage { ptr::null() }; - let fn_info = abi::FunctionInfo { - signature: abi::FunctionSignature { + let fn_info = FunctionInfo { + signature: FunctionSignature { name: name.as_ptr(), arg_types: type_infos.as_ptr() as *const *const _, return_type, @@ -49,11 +49,7 @@ impl FunctionInfoStorage { /// A value-to-`FunctionInfo` conversion that consumes the input value. pub trait IntoFunctionInfo { /// Performs the conversion. - fn into>( - self, - name: S, - privacy: abi::Privacy, - ) -> (abi::FunctionInfo, FunctionInfoStorage); + fn into>(self, name: S, privacy: Privacy) -> (FunctionInfo, FunctionInfoStorage); } macro_rules! into_function_info_impl { @@ -64,7 +60,7 @@ macro_rules! into_function_info_impl { impl<$R: HasStaticTypeInfo, $($T: HasStaticTypeInfo,)*> IntoFunctionInfo for extern "C" fn($($T),*) -> $R { - fn into>(self, name: S, privacy: abi::Privacy) -> (abi::FunctionInfo, FunctionInfoStorage) { + fn into>(self, name: S, privacy: Privacy) -> (FunctionInfo, FunctionInfoStorage) { FunctionInfoStorage::new_function( name.as_ref(), &[$($T::type_info(),)*], @@ -78,7 +74,7 @@ macro_rules! into_function_info_impl { impl<$($T: HasStaticTypeInfo,)*> IntoFunctionInfo for extern "C" fn($($T),*) { - fn into>(self, name: S, privacy: abi::Privacy) -> (abi::FunctionInfo, FunctionInfoStorage) { + fn into>(self, name: S, privacy: Privacy) -> (FunctionInfo, FunctionInfoStorage) { FunctionInfoStorage::new_function( name.as_ref(), &[$($T::type_info(),)*], diff --git a/crates/mun_abi/src/lib.rs b/crates/mun_abi/src/lib.rs index 050fc2b3d..f4b4c958a 100644 --- a/crates/mun_abi/src/lib.rs +++ b/crates/mun_abi/src/lib.rs @@ -7,15 +7,20 @@ // Bindings can be manually generated by running `cargo gen-abi`. mod autogen; mod autogen_impl; +mod function_info; +mod static_type_map; +mod type_info; pub use autogen::*; +pub use function_info::{FunctionInfoStorage, IntoFunctionInfo}; +pub use type_info::HasStaticTypeInfo; /// The Mun ABI prelude /// /// The *prelude* contains imports that are used almost every time. pub mod prelude { pub use crate::autogen::*; - pub use crate::{Privacy, StructMemoryKind, TypeGroup}; + pub use crate::{HasStaticTypeInfo, IntoFunctionInfo, Privacy, StructMemoryKind, TypeGroup}; } /// Represents the kind of memory management a struct uses. diff --git a/crates/mun_runtime/src/static_type_map.rs b/crates/mun_abi/src/static_type_map.rs similarity index 100% rename from crates/mun_runtime/src/static_type_map.rs rename to crates/mun_abi/src/static_type_map.rs diff --git a/crates/mun_runtime/src/type_info.rs b/crates/mun_abi/src/type_info.rs similarity index 81% rename from crates/mun_runtime/src/type_info.rs rename to crates/mun_abi/src/type_info.rs index cef4ff4c2..666205595 100644 --- a/crates/mun_runtime/src/type_info.rs +++ b/crates/mun_abi/src/type_info.rs @@ -1,18 +1,18 @@ -use super::static_type_map::StaticTypeMap; +use crate::{static_type_map::StaticTypeMap, Guid, TypeGroup, TypeInfo}; use once_cell::sync::OnceCell; use std::convert::TryInto; use std::ffi::{CStr, CString}; use std::sync::Once; -/// A trait that defines that for a type we can statically return a abi::TypeInfo +/// A trait that defines that for a type we can statically return a `TypeInfo`. pub trait HasStaticTypeInfo { /// Returns a reference to the TypeInfo for the type - fn type_info() -> &'static abi::TypeInfo; + fn type_info() -> &'static TypeInfo; } /// A trait that defines that for a type we can statically return the name that would be used in a -/// abi::TypeInfo. This is useful for opaque types that we do not know the full details of but we -/// could use it as a pointer type +/// `TypeInfo`. This is useful for opaque types that we do not know the full details of but we could +/// use it as a pointer type pub trait HasStaticTypeInfoName { /// Returns the type info name for the type fn type_name() -> &'static CStr; @@ -27,8 +27,8 @@ impl HasStaticTypeInfoName for T { /// Every type that has at least a type name also has a valid pointer type name impl HasStaticTypeInfo for *const T { - fn type_info() -> &'static abi::TypeInfo { - static mut VALUE: Option> = None; + fn type_info() -> &'static TypeInfo { + static mut VALUE: Option> = None; static INIT: Once = Once::new(); let map = unsafe { @@ -41,16 +41,16 @@ impl HasStaticTypeInfo for *const T { &map.call_once::(|| { let name = CString::new(format!("*const {}", T::type_name().to_str().unwrap())).unwrap(); - let guid = abi::Guid { + let guid = Guid { b: md5::compute(&name.as_bytes()).0, }; let name_ptr = name.as_ptr(); ( name, - abi::TypeInfo { + TypeInfo { guid, name: name_ptr, - group: abi::TypeGroup::FundamentalTypes, + group: TypeGroup::FundamentalTypes, size_in_bits: (std::mem::size_of::<*const T>() * 8) .try_into() .expect("size of T is larger than the maximum allowed ABI size. Please file a bug."), @@ -66,8 +66,8 @@ impl HasStaticTypeInfo for *const T { /// Every type that has at least a type name also has a valid pointer type name impl HasStaticTypeInfo for *mut T { - fn type_info() -> &'static abi::TypeInfo { - static mut VALUE: Option> = None; + fn type_info() -> &'static TypeInfo { + static mut VALUE: Option> = None; static INIT: Once = Once::new(); let map = unsafe { @@ -79,16 +79,16 @@ impl HasStaticTypeInfo for *mut T { &map.call_once::(|| { let name = CString::new(format!("*mut {}", T::type_name().to_str().unwrap())).unwrap(); - let guid = abi::Guid { + let guid = Guid { b: md5::compute(&name.as_bytes()).0, }; let name_ptr = name.as_ptr(); ( name, - abi::TypeInfo { + TypeInfo { guid, name: name_ptr, - group: abi::TypeGroup::FundamentalTypes, + group: TypeGroup::FundamentalTypes, size_in_bits: (std::mem::size_of::<*const T>() * 8) .try_into() .expect("size of T is larger than the maximum allowed ABI size. Please file a bug."), @@ -108,17 +108,17 @@ macro_rules! impl_basic_type_info { ),+) => { $( impl HasStaticTypeInfo for $ty { - fn type_info() -> &'static abi::TypeInfo { - static TYPE_INFO: OnceCell = OnceCell::new(); + fn type_info() -> &'static TypeInfo { + static TYPE_INFO: OnceCell = OnceCell::new(); TYPE_INFO.get_or_init(|| { static TYPE_INFO_NAME: OnceCell = OnceCell::new(); let type_info_name: &'static CString = TYPE_INFO_NAME .get_or_init(|| CString::new(format!("core::{}", stringify!($ty))).unwrap()); - abi::TypeInfo { - guid: abi::Guid{ b: md5::compute(&type_info_name.as_bytes()).0 }, + TypeInfo { + guid: Guid{ b: md5::compute(&type_info_name.as_bytes()).0 }, name: type_info_name.as_ptr(), - group: abi::TypeGroup::FundamentalTypes, + group: TypeGroup::FundamentalTypes, size_in_bits: (std::mem::size_of::<$ty>() * 8) .try_into() .expect("size of T is larger than the maximum allowed ABI size. Please file a bug."), @@ -153,33 +153,34 @@ macro_rules! impl_has_type_info_name { impl_basic_type_info!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, f32, f64, bool); impl_has_type_info_name!( - std::ffi::c_void => "core::void" + std::ffi::c_void => "core::void", + TypeInfo => "TypeInfo" ); #[cfg(target_pointer_width = "64")] impl HasStaticTypeInfo for usize { - fn type_info() -> &'static abi::TypeInfo { + fn type_info() -> &'static TypeInfo { u64::type_info() } } #[cfg(target_pointer_width = "64")] impl HasStaticTypeInfo for isize { - fn type_info() -> &'static abi::TypeInfo { + fn type_info() -> &'static TypeInfo { i64::type_info() } } #[cfg(target_pointer_width = "32")] impl HasStaticTypeInfo for usize { - fn type_info() -> &'static abi::TypeInfo { + fn type_info() -> &'static TypeInfo { u32::type_info() } } #[cfg(target_pointer_width = "32")] impl HasStaticTypeInfo for isize { - fn type_info() -> &'static abi::TypeInfo { + fn type_info() -> &'static TypeInfo { i32::type_info() } } diff --git a/crates/mun_memory/Cargo.toml b/crates/mun_memory/Cargo.toml index eed4796f8..08da8940d 100644 --- a/crates/mun_memory/Cargo.toml +++ b/crates/mun_memory/Cargo.toml @@ -10,6 +10,7 @@ edition = "2018" abi = { path = "../mun_abi", package = "mun_abi" } once_cell = "1.3.1" parking_lot = "0.10" +lazy_static = "1.4.0" [dev-dependencies] paste = "0.1" diff --git a/crates/mun_memory/src/cast.rs b/crates/mun_memory/src/cast.rs new file mode 100644 index 000000000..47c0a2c7e --- /dev/null +++ b/crates/mun_memory/src/cast.rs @@ -0,0 +1,250 @@ +use abi::HasStaticTypeInfo; +use lazy_static::lazy_static; +use std::{collections::HashMap, ptr::NonNull}; + +type CastFn = fn(NonNull, NonNull); + +macro_rules! insert_cast_fn { + { $table:ident, $A:ty, $B:ty } => { + $table.insert( + (<$A>::type_info().guid, <$B>::type_info().guid), + cast_from_to::<$A, $B> as CastFn, + ) + } +} + +lazy_static! { + static ref CAST_FN_TABLE: HashMap<(abi::Guid, abi::Guid), CastFn> = { + let mut table = HashMap::new(); + insert_cast_fn!(table, f32, f64); + insert_cast_fn!(table, i8, i16); + insert_cast_fn!(table, i8, i32); + insert_cast_fn!(table, i8, i64); + insert_cast_fn!(table, i8, i128); + insert_cast_fn!(table, i16, i32); + insert_cast_fn!(table, i16, i64); + insert_cast_fn!(table, i16, i128); + insert_cast_fn!(table, i32, i64); + insert_cast_fn!(table, i32, i128); + insert_cast_fn!(table, i64, i128); + insert_cast_fn!(table, u8, i16); + insert_cast_fn!(table, u8, u16); + insert_cast_fn!(table, u8, i32); + insert_cast_fn!(table, u8, u32); + insert_cast_fn!(table, u8, i64); + insert_cast_fn!(table, u8, u64); + insert_cast_fn!(table, u8, i128); + insert_cast_fn!(table, u8, u128); + insert_cast_fn!(table, u16, i32); + insert_cast_fn!(table, u16, u32); + insert_cast_fn!(table, u16, i64); + insert_cast_fn!(table, u16, u64); + insert_cast_fn!(table, u16, i128); + insert_cast_fn!(table, u16, u128); + insert_cast_fn!(table, u32, i64); + insert_cast_fn!(table, u32, u64); + insert_cast_fn!(table, u32, i128); + insert_cast_fn!(table, u32, u128); + insert_cast_fn!(table, u64, i128); + insert_cast_fn!(table, u64, u128); + table + }; +} + +fn cast_from_to(src: NonNull, dest: NonNull) +where + A: Copy + Into, +{ + let value = unsafe { *src.cast::().as_ref() }; + unsafe { *dest.cast::().as_mut() = value.into() }; +} + +pub fn try_cast_from_to( + old_guid: abi::Guid, + new_guid: abi::Guid, + src: NonNull, + dest: NonNull, +) -> bool { + if let Some(cast_fn) = CAST_FN_TABLE.get(&(old_guid, new_guid)) { + cast_fn(src, dest); + true + } else { + false + } +} + +#[cfg(test)] +mod tests { + use super::try_cast_from_to; + use abi::HasStaticTypeInfo; + use std::ptr::NonNull; + + fn assert_cast(a: A, mut b: B) + where + A: Copy + Into + HasStaticTypeInfo, + B: PartialEq + std::fmt::Debug + HasStaticTypeInfo, + { + assert!(try_cast_from_to( + A::type_info().guid, + B::type_info().guid, + unsafe { NonNull::new_unchecked(&a as *const _ as *mut _) }, + unsafe { NonNull::new_unchecked(&mut b as *mut _) }.cast::(), + )); + assert_eq!(b, a.into()); + } + + #[test] + fn cast_f32_to_f64() { + assert_cast(3.14f32, 0f64); + } + + #[test] + fn cast_i8_to_i16() { + assert_cast(-5i8, 0i16); + } + + #[test] + fn cast_i8_to_i32() { + assert_cast(-5i8, 0i32); + } + + #[test] + fn cast_i8_to_i64() { + assert_cast(-5i8, 0i64); + } + + #[test] + fn cast_i8_to_i128() { + assert_cast(-5i8, 0i128); + } + + #[test] + fn cast_i16_to_i32() { + assert_cast(-5i16, 0i32); + } + + #[test] + fn cast_i16_to_i64() { + assert_cast(-5i16, 0i64); + } + + #[test] + fn cast_i16_to_i128() { + assert_cast(-5i16, 0i128); + } + + #[test] + fn cast_i32_to_i64() { + assert_cast(-5i32, 0i64); + } + + #[test] + fn cast_i32_to_i128() { + assert_cast(-5i32, 0i128); + } + + #[test] + fn cast_i64_to_i128() { + assert_cast(-5i64, 0i128); + } + + #[test] + fn cast_u8_to_i16() { + assert_cast(5u8, 0i16); + } + + #[test] + fn cast_u8_to_u16() { + assert_cast(5u8, 0u16); + } + + #[test] + fn cast_u8_to_i32() { + assert_cast(5u8, 0i32); + } + + #[test] + fn cast_u8_to_u32() { + assert_cast(5u8, 0u32); + } + + #[test] + fn cast_u8_to_i64() { + assert_cast(5u8, 0i64); + } + + #[test] + fn cast_u8_to_u64() { + assert_cast(5u8, 0u64); + } + + #[test] + fn cast_u8_to_i128() { + assert_cast(5u8, 0i128); + } + + #[test] + fn cast_u8_to_u128() { + assert_cast(5u8, 0u128); + } + + #[test] + fn cast_u16_to_i32() { + assert_cast(5u16, 0i32); + } + + #[test] + fn cast_u16_to_u32() { + assert_cast(5u16, 0u32); + } + + #[test] + fn cast_u16_to_i64() { + assert_cast(5u16, 0i64); + } + + #[test] + fn cast_u16_to_u64() { + assert_cast(5u16, 0u64); + } + + #[test] + fn cast_u16_to_i128() { + assert_cast(5u16, 0i128); + } + + #[test] + fn cast_u16_to_u128() { + assert_cast(5u16, 0u128); + } + + #[test] + fn cast_u32_to_i64() { + assert_cast(5u32, 0i64); + } + + #[test] + fn cast_u32_to_u64() { + assert_cast(5u32, 0u64); + } + + #[test] + fn cast_u32_to_i128() { + assert_cast(5u32, 0i128); + } + + #[test] + fn cast_u32_to_u128() { + assert_cast(5u32, 0u128); + } + + #[test] + fn cast_u64_to_i128() { + assert_cast(5u64, 0i128); + } + + #[test] + fn cast_u64_to_u128() { + assert_cast(5u64, 0u128); + } +} diff --git a/crates/mun_memory/src/gc/mark_sweep.rs b/crates/mun_memory/src/gc/mark_sweep.rs index a518be2b5..9df89a567 100644 --- a/crates/mun_memory/src/gc/mark_sweep.rs +++ b/crates/mun_memory/src/gc/mark_sweep.rs @@ -1,8 +1,9 @@ use crate::{ + cast, diff::{Diff, FieldDiff}, gc::{Event, GcPtr, GcRuntime, Observer, RawGcPtr, Stats, TypeTrace}, mapping::{self, field_mapping, FieldMappingDesc, MemoryMapper}, - TypeFields, TypeLayout, + TypeDesc, TypeFields, TypeLayout, }; use once_cell::unsync::OnceCell; use parking_lot::RwLock; @@ -11,6 +12,7 @@ use std::{ hash::Hash, ops::Deref, pin::Pin, + ptr::NonNull, }; /// Implements a simple mark-sweep type garbage collector. @@ -198,7 +200,7 @@ where impl MemoryMapper for MarkSweep where - T: TypeLayout + TypeFields + TypeTrace + Clone + Eq + Hash, + T: TypeDesc + TypeLayout + TypeFields + TypeTrace + Clone + Eq + Hash, O: Observer, { fn map_memory(&self, old: &[T], new: &[T], diff: &[Diff]) -> Vec { @@ -256,12 +258,12 @@ where struct TypeData<'a, T> { old_fields: Vec<(&'a str, T)>, - _new_fields: Vec<(&'a str, T)>, + new_fields: Vec<(&'a str, T)>, old_offsets: &'a [u16], new_offsets: &'a [u16], } - fn map_fields<'a, T: TypeLayout + TypeFields + TypeTrace + Clone + Eq>( + fn map_fields<'a, T: TypeDesc + TypeLayout + TypeFields + TypeTrace + Clone + Eq>( object_info: &mut Pin>>, old_ty: &'a T, new_ty: &'a T, @@ -270,12 +272,12 @@ where ) { let TypeData { old_fields, - _new_fields, + new_fields, old_offsets, new_offsets, } = type_data.get_or_init(|| TypeData { old_fields: old_ty.fields(), - _new_fields: new_ty.fields(), + new_fields: new_ty.fields(), old_offsets: old_ty.offsets(), new_offsets: new_ty.offsets(), }); @@ -296,7 +298,15 @@ where }; let old_field = unsafe { old_fields.get_unchecked(old_index) }; if action == mapping::Action::Cast { - panic!("The Mun Runtime doesn't currently support casting"); + let new_field = unsafe { new_fields.get_unchecked(new_index) }; + if !cast::try_cast_from_to( + *old_field.1.guid(), + *new_field.1.guid(), + unsafe { NonNull::new_unchecked(src) }, + unsafe { NonNull::new_unchecked(dest) }, + ) { + // Failed to cast. Use the previously zero-initialized value instead + } } else { unsafe { std::ptr::copy_nonoverlapping(src, dest, old_field.1.layout().size()) diff --git a/crates/mun_memory/src/lib.rs b/crates/mun_memory/src/lib.rs index a5628f531..b076a6121 100644 --- a/crates/mun_memory/src/lib.rs +++ b/crates/mun_memory/src/lib.rs @@ -1,5 +1,6 @@ use std::alloc::Layout; +mod cast; pub mod diff; pub mod gc; pub mod mapping; diff --git a/crates/mun_memory/tests/diff/mod.rs b/crates/mun_memory/tests/diff/mod.rs index a845572c9..738e498ee 100644 --- a/crates/mun_memory/tests/diff/mod.rs +++ b/crates/mun_memory/tests/diff/mod.rs @@ -8,8 +8,8 @@ use util::*; #[test] fn add() { - let int = TypeInfo::new_fundamental::(INT_NAME, INT_GUID); - let float = TypeInfo::new_fundamental::(FLOAT_NAME, FLOAT_GUID); + let int = TypeInfo::new_fundamental::(); + let float = TypeInfo::new_fundamental::(); let struct1 = TypeInfo::new_struct( STRUCT1_NAME, STRUCT1_GUID, diff --git a/crates/mun_memory/tests/diff/primitives.rs b/crates/mun_memory/tests/diff/primitives.rs index 09123b93a..5a1cf9f61 100644 --- a/crates/mun_memory/tests/diff/primitives.rs +++ b/crates/mun_memory/tests/diff/primitives.rs @@ -3,8 +3,8 @@ use mun_memory::diff::{diff, Diff}; #[test] fn add() { - let int = TypeInfo::new_fundamental::(INT_NAME, INT_GUID); - let float = TypeInfo::new_fundamental::(FLOAT_NAME, FLOAT_GUID); + let int = TypeInfo::new_fundamental::(); + let float = TypeInfo::new_fundamental::(); let old = &[&int]; let new = &[&int, &float]; @@ -16,8 +16,8 @@ fn add() { #[test] fn remove() { - let int = TypeInfo::new_fundamental::(INT_NAME, INT_GUID); - let float = TypeInfo::new_fundamental::(FLOAT_NAME, FLOAT_GUID); + let int = TypeInfo::new_fundamental::(); + let float = TypeInfo::new_fundamental::(); let old = &[&int, &float]; let new = &[&float]; @@ -29,8 +29,8 @@ fn remove() { #[test] fn replace() { - let int = TypeInfo::new_fundamental::(INT_NAME, INT_GUID); - let float = TypeInfo::new_fundamental::(FLOAT_NAME, FLOAT_GUID); + let int = TypeInfo::new_fundamental::(); + let float = TypeInfo::new_fundamental::(); let old = &[&int]; let new = &[&float]; @@ -45,8 +45,8 @@ fn replace() { #[test] fn swap() { - let int = TypeInfo::new_fundamental::(INT_NAME, INT_GUID); - let float = TypeInfo::new_fundamental::(FLOAT_NAME, FLOAT_GUID); + let int = TypeInfo::new_fundamental::(); + let float = TypeInfo::new_fundamental::(); let old = &[&int, &float]; let new = &[&float, &int]; diff --git a/crates/mun_memory/tests/diff/structs.rs b/crates/mun_memory/tests/diff/structs.rs index 3a2d82906..3f2774c2a 100644 --- a/crates/mun_memory/tests/diff/structs.rs +++ b/crates/mun_memory/tests/diff/structs.rs @@ -14,8 +14,8 @@ fn assert_eq_struct(result: &[TypeInfo], expected: &[TypeInfo]) { #[test] fn add() { - let int = TypeInfo::new_fundamental::(INT_NAME, INT_GUID); - let float = TypeInfo::new_fundamental::(FLOAT_NAME, FLOAT_GUID); + let int = TypeInfo::new_fundamental::(); + let float = TypeInfo::new_fundamental::(); let struct1 = TypeInfo::new_struct( STRUCT1_NAME, @@ -41,8 +41,8 @@ fn add() { #[test] fn remove() { - let int = TypeInfo::new_fundamental::(INT_NAME, INT_GUID); - let float = TypeInfo::new_fundamental::(FLOAT_NAME, FLOAT_GUID); + let int = TypeInfo::new_fundamental::(); + let float = TypeInfo::new_fundamental::(); let struct1 = TypeInfo::new_struct( STRUCT1_NAME, @@ -65,8 +65,8 @@ fn remove() { #[test] fn replace() { - let int = TypeInfo::new_fundamental::(INT_NAME, INT_GUID); - let float = TypeInfo::new_fundamental::(FLOAT_NAME, FLOAT_GUID); + let int = TypeInfo::new_fundamental::(); + let float = TypeInfo::new_fundamental::(); let struct1 = TypeInfo::new_struct( STRUCT1_NAME, @@ -92,8 +92,8 @@ fn replace() { #[test] fn swap() { - let int = TypeInfo::new_fundamental::(INT_NAME, INT_GUID); - let float = TypeInfo::new_fundamental::(FLOAT_NAME, FLOAT_GUID); + let int = TypeInfo::new_fundamental::(); + let float = TypeInfo::new_fundamental::(); let struct1 = TypeInfo::new_struct( STRUCT1_NAME, @@ -125,8 +125,8 @@ fn swap() { #[test] fn add_field1() { - let int = TypeInfo::new_fundamental::(INT_NAME, INT_GUID); - let float = TypeInfo::new_fundamental::(FLOAT_NAME, FLOAT_GUID); + let int = TypeInfo::new_fundamental::(); + let float = TypeInfo::new_fundamental::(); let struct1 = TypeInfo::new_struct( STRUCT1_NAME, @@ -156,8 +156,8 @@ fn add_field1() { #[test] fn add_field2() { - let int = TypeInfo::new_fundamental::(INT_NAME, INT_GUID); - let float = TypeInfo::new_fundamental::(FLOAT_NAME, FLOAT_GUID); + let int = TypeInfo::new_fundamental::(); + let float = TypeInfo::new_fundamental::(); let struct1 = TypeInfo::new_struct( STRUCT1_NAME, @@ -187,8 +187,8 @@ fn add_field2() { #[test] fn add_field3() { - let int = TypeInfo::new_fundamental::(INT_NAME, INT_GUID); - let float = TypeInfo::new_fundamental::(FLOAT_NAME, FLOAT_GUID); + let int = TypeInfo::new_fundamental::(); + let float = TypeInfo::new_fundamental::(); let struct1 = TypeInfo::new_struct( STRUCT1_NAME, @@ -218,8 +218,8 @@ fn add_field3() { #[test] fn remove_field1() { - let int = TypeInfo::new_fundamental::(INT_NAME, INT_GUID); - let float = TypeInfo::new_fundamental::(FLOAT_NAME, FLOAT_GUID); + let int = TypeInfo::new_fundamental::(); + let float = TypeInfo::new_fundamental::(); let struct1 = TypeInfo::new_struct( STRUCT1_NAME, @@ -248,8 +248,8 @@ fn remove_field1() { #[test] fn remove_field2() { - let int = TypeInfo::new_fundamental::(INT_NAME, INT_GUID); - let float = TypeInfo::new_fundamental::(FLOAT_NAME, FLOAT_GUID); + let int = TypeInfo::new_fundamental::(); + let float = TypeInfo::new_fundamental::(); let struct1 = TypeInfo::new_struct( STRUCT1_NAME, @@ -278,8 +278,8 @@ fn remove_field2() { #[test] fn remove_field3() { - let int = TypeInfo::new_fundamental::(INT_NAME, INT_GUID); - let float = TypeInfo::new_fundamental::(FLOAT_NAME, FLOAT_GUID); + let int = TypeInfo::new_fundamental::(); + let float = TypeInfo::new_fundamental::(); let struct1 = TypeInfo::new_struct( STRUCT1_NAME, @@ -308,8 +308,8 @@ fn remove_field3() { #[test] fn swap_fields() { - let int = TypeInfo::new_fundamental::(INT_NAME, INT_GUID); - let float = TypeInfo::new_fundamental::(FLOAT_NAME, FLOAT_GUID); + let int = TypeInfo::new_fundamental::(); + let float = TypeInfo::new_fundamental::(); let struct1 = TypeInfo::new_struct( STRUCT1_NAME, @@ -343,8 +343,8 @@ fn swap_fields() { #[test] fn swap_fields2() { - let int = TypeInfo::new_fundamental::(INT_NAME, INT_GUID); - let float = TypeInfo::new_fundamental::(FLOAT_NAME, FLOAT_GUID); + let int = TypeInfo::new_fundamental::(); + let float = TypeInfo::new_fundamental::(); let struct1 = TypeInfo::new_struct( STRUCT1_NAME, @@ -388,10 +388,54 @@ fn swap_fields2() { assert_eq_struct(&apply_diff(old, new, diff), &vec![struct2.clone()]); } +#[test] +fn cast_field() { + let int = TypeInfo::new_fundamental::(); + let float = TypeInfo::new_fundamental::(); + + let struct1 = TypeInfo::new_struct( + STRUCT1_NAME, + STRUCT1_GUID, + StructInfo::new(&[("a", &int), ("b", &float), ("c", &float)]), + ); + let struct2 = TypeInfo::new_struct( + STRUCT1_NAME, + STRUCT2_GUID, + StructInfo::new(&[("a", &float), ("b", &int), ("c", &int)]), + ); + + let old = &[&struct1]; + let new = &[&struct2]; + + let diff = diff(old, new); + assert_eq!( + diff, + vec![Diff::Edit { + diff: vec![ + FieldDiff::Edit { + index: 0, + kind: FieldEditKind::ConvertType, + }, + FieldDiff::Edit { + index: 1, + kind: FieldEditKind::ConvertType, + }, + FieldDiff::Edit { + index: 2, + kind: FieldEditKind::ConvertType, + } + ], + old_index: 0, + new_index: 0, + }] + ); + assert_eq_struct(&apply_diff(old, new, diff), &vec![struct2.clone()]); +} + #[test] fn rename_field1() { - let int = TypeInfo::new_fundamental::(INT_NAME, INT_GUID); - let float = TypeInfo::new_fundamental::(FLOAT_NAME, FLOAT_GUID); + let int = TypeInfo::new_fundamental::(); + let float = TypeInfo::new_fundamental::(); let struct1 = TypeInfo::new_struct( STRUCT1_NAME, @@ -424,8 +468,8 @@ fn rename_field1() { #[test] fn rename_field2() { - let int = TypeInfo::new_fundamental::(INT_NAME, INT_GUID); - let float = TypeInfo::new_fundamental::(FLOAT_NAME, FLOAT_GUID); + let int = TypeInfo::new_fundamental::(); + let float = TypeInfo::new_fundamental::(); let struct1 = TypeInfo::new_struct( STRUCT1_NAME, diff --git a/crates/mun_memory/tests/diff/util.rs b/crates/mun_memory/tests/diff/util.rs index 4c9eacc2a..7c9375eb3 100644 --- a/crates/mun_memory/tests/diff/util.rs +++ b/crates/mun_memory/tests/diff/util.rs @@ -5,14 +5,6 @@ use mun_memory::{ }; use std::alloc::Layout; -pub const INT_NAME: &str = "int"; -pub const INT_GUID: abi::Guid = abi::Guid { - b: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], -}; -pub const FLOAT_NAME: &str = "float"; -pub const FLOAT_GUID: abi::Guid = abi::Guid { - b: [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0], -}; pub const STRUCT1_NAME: &str = "struct1"; pub const STRUCT1_GUID: abi::Guid = abi::Guid { b: [ @@ -70,10 +62,11 @@ pub struct TypeInfo { } impl TypeInfo { - pub fn new_fundamental(name: &str, guid: abi::Guid) -> Self { + pub fn new_fundamental() -> Self { + let type_info = T::type_info(); Self { - name: name.to_string(), - guid, + name: type_info.name().to_string(), + guid: type_info.guid, group: abi::TypeGroup::FundamentalTypes, layout: Layout::new::(), tail: TypeInfoTail::Empty, @@ -254,10 +247,8 @@ fn apply_mapping<'t>(old: &mut TypeInfo, new: &TypeInfo, mapping: &[FieldDiff]) new_field: &(String, TypeInfo), ) { match *kind { - FieldEditKind::ConvertType => panic!("Casting is currently not supported"), - FieldEditKind::Rename => { - old_field.0 = new_field.0.clone(); - } + FieldEditKind::ConvertType => old_field.1 = new_field.1.clone(), + FieldEditKind::Rename => old_field.0 = new_field.0.clone(), } } diff --git a/crates/mun_runtime/Cargo.toml b/crates/mun_runtime/Cargo.toml index affb129ed..d46442cb9 100644 --- a/crates/mun_runtime/Cargo.toml +++ b/crates/mun_runtime/Cargo.toml @@ -12,12 +12,11 @@ description = "A runtime for hot reloading and invoking Mun from Rust" abi = { path = "../mun_abi", package = "mun_abi" } failure = "0.1.7" libloading = "0.5" -md5= "0.7.0" +md5 = "0.7.0" memory = { path = "../mun_memory", package = "mun_memory" } notify = "4.0.12" parking_lot = "0.10" tempfile = "3" -once_cell = "1.3.1" rustc-hash = "1.1" [dev-dependencies] diff --git a/crates/mun_runtime/src/lib.rs b/crates/mun_runtime/src/lib.rs index 17ce98b4a..f2e063616 100644 --- a/crates/mun_runtime/src/lib.rs +++ b/crates/mun_runtime/src/lib.rs @@ -5,19 +5,15 @@ #![warn(missing_docs)] mod assembly; -mod function; #[macro_use] mod macros; #[macro_use] -mod type_info; mod garbage_collector; mod marshal; mod reflection; -mod static_type_map; mod r#struct; use failure::Error; -use function::FunctionInfoStorage; use garbage_collector::GarbageCollector; use memory::gc::{self, GcRuntime}; use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher}; @@ -36,15 +32,11 @@ use std::{ pub use crate::{ assembly::Assembly, - function::IntoFunctionInfo, marshal::Marshal, r#struct::StructRef, reflection::{ArgumentReflection, ReturnTypeReflection}, }; - -impl_has_type_info_name!( - abi::TypeInfo => "TypeInfo" -); +pub use abi::IntoFunctionInfo; /// Options for the construction of a [`Runtime`]. pub struct RuntimeOptions { @@ -53,7 +45,7 @@ pub struct RuntimeOptions { /// Delay during which filesystem events are collected, deduplicated, and after which emitted. pub delay: Duration, /// Custom user injected functions - pub user_functions: Vec<(abi::FunctionInfo, FunctionInfoStorage)>, + pub user_functions: Vec<(abi::FunctionInfo, abi::FunctionInfoStorage)>, } /// A builder for the [`Runtime`]. @@ -64,30 +56,27 @@ pub struct RuntimeBuilder { impl RuntimeBuilder { /// Constructs a new `RuntimeBuilder` for the shared library at `library_path`. pub fn new>(library_path: P) -> Self { - let mut result = Self { + Self { options: RuntimeOptions { library_path: library_path.into(), delay: Duration::from_millis(10), user_functions: Default::default(), }, - }; - - result.insert_fn( + } + .insert_fn( "new", new as extern "C" fn(*const abi::TypeInfo, *mut ffi::c_void) -> *const *mut ffi::c_void, - ); - - result + ) } /// Sets the `delay`. - pub fn set_delay(&mut self, delay: Duration) -> &mut Self { + pub fn set_delay(mut self, delay: Duration) -> Self { self.options.delay = delay; self } /// Adds a custom user function to the dispatch table. - pub fn insert_fn, F: IntoFunctionInfo>(&mut self, name: S, func: F) -> &mut Self { + pub fn insert_fn, F: abi::IntoFunctionInfo>(mut self, name: S, func: F) -> Self { self.options .user_functions .push(func.into(name, abi::Privacy::Public)); @@ -176,7 +165,7 @@ pub struct Runtime { watcher: RecommendedWatcher, watcher_rx: Receiver, gc: Arc, - _user_functions: Vec, + _user_functions: Vec, } /// Retrieve the allocator using the provided handle. diff --git a/crates/mun_runtime/src/reflection.rs b/crates/mun_runtime/src/reflection.rs index a08734ef7..6f6db7212 100644 --- a/crates/mun_runtime/src/reflection.rs +++ b/crates/mun_runtime/src/reflection.rs @@ -1,5 +1,5 @@ -use crate::type_info::HasStaticTypeInfo; use crate::{marshal::Marshal, Runtime, StructRef}; +use abi::HasStaticTypeInfo; /// Returns whether the specified argument type matches the `type_info`. pub fn equals_argument_type<'r, 'e, 'f, T: ArgumentReflection>( diff --git a/crates/mun_runtime/tests/memory.rs b/crates/mun_runtime/tests/memory.rs index 67233a4bb..2f7ac05d2 100644 --- a/crates/mun_runtime/tests/memory.rs +++ b/crates/mun_runtime/tests/memory.rs @@ -232,6 +232,77 @@ fn map_struct_remove_field3() { assert_eq!(foo.get::("a").unwrap(), a); } +#[test] +fn map_struct_cast_fields1() { + let mut driver = TestDriver::new( + r#" + struct Foo( + u8, + i16, + u32, + i64, + f32, + ) + + pub fn foo_new(a: u8, b: i16, c: u32, d: i64, e: f32) -> Foo { + Foo(a, b, c, d, e) + } + "#, + ); + + let a = 1u8; + let b = -2i16; + let c = 3u32; + let d = -4i64; + let e = 3.14f32; + let foo: StructRef = invoke_fn!(driver.runtime_mut(), "foo_new", a, b, c, d, e).unwrap(); + + driver.update( + r#" + struct Foo( + u16, + i32, + u64, + i128, + f64, + ) + "#, + ); + assert_eq!(foo.get::("0").unwrap(), a.into()); + assert_eq!(foo.get::("1").unwrap(), b.into()); + assert_eq!(foo.get::("2").unwrap(), c.into()); + assert_eq!(foo.get::("3").unwrap(), d.into()); + assert_eq!(foo.get::("4").unwrap(), e.into()); +} + +#[test] +fn map_struct_cast_fields2() { + let mut driver = TestDriver::new( + r#" + struct Foo( + i16, + ) + + pub fn foo_new(a: i16) -> Foo { + Foo(a) + } + "#, + ); + + let a = -2i16; + let foo: StructRef = invoke_fn!(driver.runtime_mut(), "foo_new", a).unwrap(); + + driver.update( + r#" + struct Foo( + u16, // Cannot convert from `i16` to `u16` + ) + "#, + ); + + assert_eq!(foo.get::("0").unwrap(), 0); +} + #[test] fn map_struct_swap_fields1() { let mut driver = TestDriver::new( diff --git a/crates/mun_runtime/tests/util.rs b/crates/mun_runtime/tests/util.rs index 8f5fcb313..fb5ca33a0 100644 --- a/crates/mun_runtime/tests/util.rs +++ b/crates/mun_runtime/tests/util.rs @@ -90,8 +90,10 @@ impl TestDriver { /// Adds a custom user function to the dispatch table. pub fn insert_fn, F: IntoFunctionInfo>(mut self, name: S, func: F) -> Self { - match &mut self.runtime { - RuntimeOrBuilder::Builder(builder) => builder.insert_fn(name, func), + self.runtime = match self.runtime { + RuntimeOrBuilder::Builder(builder) => { + RuntimeOrBuilder::Builder(builder.insert_fn(name, func)) + } _ => unreachable!(), }; self