Skip to content

Commit

Permalink
fix(rs-port): make user-data accept any type of data instead of metac…
Browse files Browse the repository at this point in the history
…all values

- **NOTE:** there's a *segmentation fault* should be solved
  • Loading branch information
hulxv committed Sep 29, 2024
1 parent 0962259 commit 67b5858
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 59 deletions.
6 changes: 3 additions & 3 deletions source/ports/rs_port/src/metacall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{
cstring_enum, parsers,
types::{MetacallError, MetacallNull, MetacallValue},
};
use std::ffi::c_void;
use std::{ffi::c_void, fmt::Debug};

// Used for documentation.
#[allow(unused_imports)]
Expand Down Expand Up @@ -38,7 +38,7 @@ fn metacall_inner(
/// ```
/// let sum = metacall::metacall_untyped("sum", [1, 2]).unwrap();
/// ```
pub fn metacall_untyped<T:'static>(
pub fn metacall_untyped<T: 'static + Debug>(
func: impl ToString,
args: impl IntoIterator<Item = impl MetacallValue>,
) -> Result<Box<dyn MetacallValue>, MetacallError> {
Expand All @@ -50,7 +50,7 @@ pub fn metacall_untyped<T:'static>(
/// ```
/// let greet = metacall::metacall_untyped_no_arg("sum").unwrap();
/// ```
pub fn metacall_untyped_no_arg<T: 'static>(
pub fn metacall_untyped_no_arg<T: 'static + Debug>(
func: impl ToString,
) -> Result<Box<dyn MetacallValue>, MetacallError> {
metacall_untyped::<T>(func, [] as [MetacallNull; 0])
Expand Down
8 changes: 5 additions & 3 deletions source/ports/rs_port/src/parsers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
MetacallObject, MetacallPointer, MetacallThrowable, MetacallValue,
},
};
use std::{collections::HashMap, ffi::c_void};
use std::{collections::HashMap, ffi::c_void, fmt::Debug};

fn metacallobj_result_wrap<T: MetacallValue>(
v: Result<T, Box<dyn MetacallValue>>,
Expand Down Expand Up @@ -53,7 +53,7 @@ pub fn raw_to_metacallobj_leak<T: MetacallValue>(
}
}

pub fn raw_to_metacallobj_untyped<T: 'static>(ret: *mut c_void) -> Box<dyn MetacallValue> {
pub fn raw_to_metacallobj_untyped<T: Debug + 'static>(ret: *mut c_void) -> Box<dyn MetacallValue> {
match (ret.is_null(), unsafe { metacall_value_id(ret) }) {
(true, _) => metacallobj_result_wrap(MetacallNull::from_metacall_raw(ret)),
(_, 0) => metacallobj_result_wrap(bool::from_metacall_raw(ret)),
Expand All @@ -80,7 +80,9 @@ pub fn raw_to_metacallobj_untyped<T: 'static>(ret: *mut c_void) -> Box<dyn Metac
_ => metacallobj_result_wrap(MetacallNull::from_metacall_raw(ret)),
}
}
pub fn raw_to_metacallobj_untyped_leak<T: 'static>(ret: *mut c_void) -> Box<dyn MetacallValue> {
pub fn raw_to_metacallobj_untyped_leak<T: Debug + 'static>(
ret: *mut c_void,
) -> Box<dyn MetacallValue> {
match (ret.is_null(), unsafe { metacall_value_id(ret) }) {
(true, _) => metacallobj_result_wrap(MetacallNull::from_metacall_raw_leak(ret)),
(_, 0) => metacallobj_result_wrap(bool::from_metacall_raw_leak(ret)),
Expand Down
2 changes: 1 addition & 1 deletion source/ports/rs_port/src/types/metacall_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ impl MetacallClass {
Ok(unsafe { metacall_class_static_get(self.value_to_class(), c_name.as_ptr()) })
}
/// Gets static attribute from a class without type casting([MetacallValue](MetacallValue)).
pub fn get_attribute_untyped<T: 'static>(
pub fn get_attribute_untyped<T: 'static + Debug>(
&self,
name: impl ToString,
) -> Result<Box<dyn MetacallValue>, MetacallGetAttributeError> {
Expand Down
96 changes: 50 additions & 46 deletions source/ports/rs_port/src/types/metacall_future.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ pub type MetacallFutureHandler<T> = fn(Box<dyn MetacallValue>, T);
/// ```
#[repr(C)]
pub struct MetacallFuture<T> {
data: *mut dyn MetacallValue,
data: *mut Option<T>,
leak: bool,
reject: Option<MetacallFutureHandler<T>>,
resolve: Option<MetacallFutureHandler<T>>,
Expand All @@ -81,21 +81,21 @@ impl<T> Clone for MetacallFuture<T> {
}
}
}
impl<T> Debug for MetacallFuture<T> {
impl<T: Debug> Debug for MetacallFuture<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let boxed_data = unsafe { Box::from_raw(self.data) };
let data = if boxed_data.is::<MetacallNull>() {
None
} else {
Some(format!("{:#?}", boxed_data))

let data = match Box::into(boxed_data) {
Some(data) => Some(format!("{data:#?}")),
None => None,
};
Box::leak(boxed_data);

let resolve = if self.resolve.is_none() {
"None"
} else {
"Some"
};

let reject = if self.reject.is_none() {
"None"
} else {
Expand All @@ -119,38 +119,36 @@ type MetacallFutureFFIData<T> = (
*mut T,
);

unsafe extern "C" fn resolver<T: 'static>(
unsafe extern "C" fn resolver<T: 'static + Debug>(
resolve_data: *mut c_void,
upper_data: *mut c_void,
) -> *mut c_void {
let (resolve, _, data) = *Box::from_raw(upper_data as *mut MetacallFutureFFIData<T>);
let user_data = Box::from_raw(data);

(resolve.unwrap())(
let user_data = std::ptr::read_unaligned(data);
parsers::raw_to_metacallobj_untyped_leak::<T>(resolve_data),
*user_data,
);

ptr::null_mut()
}
unsafe extern "C" fn rejecter<T: 'static>(
unsafe extern "C" fn rejecter<T: 'static + Debug>(
reject_data: *mut c_void,
upper_data: *mut c_void,
) -> *mut c_void {
let (_, reject, data) = *Box::from_raw(upper_data as *mut MetacallFutureFFIData<T>);
let user_data = Box::from_raw(data);
let user_data = std::ptr::read_unaligned(data);

(reject.unwrap())(
let result = (reject.unwrap())(
parsers::raw_to_metacallobj_untyped_leak::<T>(reject_data),
*user_data,
user_data,
);

ptr::null_mut()
Box::into_raw(result) as *mut c_void
}

impl<T: 'static> MetacallFuture<T> {
fn create_null_data() -> *mut dyn MetacallValue {
Box::into_raw(helpers::metacall_implementer_to_traitobj(MetacallNull()))
impl<T: 'static + Debug> MetacallFuture<T> {
fn create_null_data() -> *mut Option<T> {
Box::into_raw(Box::new(None))
}

#[doc(hidden)]
Expand Down Expand Up @@ -280,8 +278,10 @@ impl<T: 'static> MetacallFuture<T> {
/// .await_fut();
///}
/// ```
pub fn data(mut self, data: T) -> Self {
pub fn data(mut self, data: impl MetacallValue) -> Self {
unsafe { drop(Box::from_raw(self.data)) };
self.data = Box::into_raw(Box::new(Some(data)));

self.data = Box::into_raw(Box::new(data) as Box<dyn MetacallValue>);

Expand Down Expand Up @@ -328,18 +328,22 @@ impl<T: 'static> MetacallFuture<T> {
// ==20664== by 0x166EBE: test::__rust_begin_short_backtrace (lib.rs:655)
// ==20664== by 0x13456B: {closure#1} (lib.rs:646)
// ==20664== by 0x13456B: core::ops::function::FnOnce::call_once{{vtable-shim}} (function.rs:250)
Box::into_raw(Box::new((self.resolve, self.reject, self.data))) as *mut c_void,
self.into_raw(),
))
};
}

#[doc(hidden)]
pub fn into_raw(self) -> *mut c_void {
// TODO:
// It's not implemented in any loader as the time of writing this block of code.
// Feel free to implement as any loader adopted accepting Future as an argument.

panic!("Passing MetacallFuture as an argument is not supported!");
unsafe {
match std::ptr::read_unaligned(self.data) {
Some(data) => {
Box::into_raw(Box::new((self.resolve, self.reject, data))) as *mut c_void
}
None => Box::into_raw(Box::new((self.resolve, self.reject, MetacallNull)))
as *mut c_void,
}
}
}
}

Expand Down Expand Up @@ -382,21 +386,21 @@ module.exports = {
fn resolve<T: PartialEq<i16> + Debug>(result: Box<dyn MetacallValue>, data: T) {
let result = result.downcast::<f64>().unwrap();

assert_eq!(
assert_eq!(
result, 2.0,
"the result should be double of the passed value"
);
assert_eq!(data, 100, "data should be passed without change");
}
"the result should be double of the passed value"
);
assert_eq!(data, 100, "data should be passed without change");
}
fn reject<T>(_: Box<dyn MetacallValue>, _: T) {
panic!("It shouldnt be rejected");
}
panic!("It shouldnt be rejected");
}
let future = metacall::<MetacallFuture<i16>>("doubleValueAfterTime", [1, 2000]).unwrap();
future
future
.then(resolve::<i16>)
.catch(reject::<i16>)
.data(100)
.await_fut();
.data(100)
.await_fut();
}

#[test]
Expand All @@ -417,17 +421,17 @@ module.exports = {
loaders::from_memory("node", script).unwrap();

fn resolve<T: PartialEq<String> + Debug>(_: Box<dyn MetacallValue>, data: T) {
assert_eq!(
data,
String::from("USER_DATA"),
"data should be passed without change"
);
}
assert_eq!(
data,
String::from("USER_DATA"),
"data should be passed without change"
);
}

let future = metacall_no_arg::<MetacallFuture<String>>("func").unwrap();
future
.then(resolve::<String>)
.data(String::from("USER_DATA"))
.await_fut();
let future = metacall_no_arg::<MetacallFuture<String>>("func").unwrap();
future
.then(resolve::<String>)
.data(String::from("USER_DATA"))
.await_fut();
}
}
2 changes: 1 addition & 1 deletion source/ports/rs_port/src/types/metacall_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ impl MetacallObject {
Ok(unsafe { metacall_object_get(metacall_value_to_object(self.value), c_name.as_ptr()) })
}
/// Gets attribute from an object without type casting([MetacallValue](MetacallValue)).
pub fn get_attribute_untyped<T: 'static>(
pub fn get_attribute_untyped<T: 'static + Debug>(
&self,
name: impl ToString,
) -> Result<Box<dyn MetacallValue>, MetacallGetAttributeError> {
Expand Down
2 changes: 1 addition & 1 deletion source/ports/rs_port/src/types/metacall_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ impl MetacallValue for MetacallPointer {
}
}
/// Equivalent to Metacall future type.
impl<T: 'static> MetacallValue for MetacallFuture<T> {
impl<T: 'static + Debug> MetacallValue for MetacallFuture<T> {
fn get_metacall_id() -> u32 {
12
}
Expand Down
8 changes: 4 additions & 4 deletions source/ports/rs_port/tests/metacall_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,8 @@ fn test_future() {
"future",
MetacallNull(),
move |future| {
fn resolve(result: Box<dyn MetacallValue>, data: Box<dyn MetacallValue>) {
validate(result, data);
fn resolve<T: MetacallValue + 'static>(result: Box<dyn MetacallValue>, data: T) {
validate(result, Box::new(data));
}

future.then(resolve).data(String::from("data")).await_fut();
Expand All @@ -195,8 +195,8 @@ fn test_future() {
"future",
MetacallNull(),
move |future| {
fn reject(result: Box<dyn MetacallValue>, data: Box<dyn MetacallValue>) {
validate(result, data);
fn reject<T: 'static + MetacallValue>(result: Box<dyn MetacallValue>, data: T) {
validate(result, Box::new(data));
}

future.catch(reject).data(String::from("data")).await_fut();
Expand Down

0 comments on commit 67b5858

Please sign in to comment.