From 60fce404fa6344842c774376f49aeca9835a3be1 Mon Sep 17 00:00:00 2001 From: Katherine Kiefer Date: Tue, 9 Jul 2024 23:45:13 +1000 Subject: [PATCH] update --- crates/byondapi-macros/src/lib.rs | 60 ++++++++++++++++++---------- crates/byondapi-rs-test/src/lib.rs | 35 ++++++++-------- crates/byondapi-rs/src/lib.rs | 1 + crates/byondapi-rs/src/threadsync.rs | 25 ++++++++++++ 4 files changed, 84 insertions(+), 37 deletions(-) create mode 100644 crates/byondapi-rs/src/threadsync.rs diff --git a/crates/byondapi-macros/src/lib.rs b/crates/byondapi-macros/src/lib.rs index 5d36f1a..7620861 100644 --- a/crates/byondapi-macros/src/lib.rs +++ b/crates/byondapi-macros/src/lib.rs @@ -46,19 +46,29 @@ pub fn bind(attr: TokenStream, item: TokenStream) -> TokenStream { let args = &input.sig.inputs; //Check for returns - match &input.sig.output { - syn::ReturnType::Default => {} // - - syn::ReturnType::Type(_, ty) => { - return syn::Error::new(ty.span(), "Do not specify the return value of binds") - .to_compile_error() - .into() + let func_return = match &input.sig.output { + syn::ReturnType::Default => { + return syn::Error::new( + input.span(), + "Empty returns are not allowed, please return a Result", + ) + .to_compile_error() + .into() } - } + + syn::ReturnType::Type(_, ty) => match ty.as_ref() { + &syn::Type::Path(_) => &input.sig.output, + _ => { + return syn::Error::new(input.span(), "Invalid return type, please return a Result") + .to_compile_error() + .into() + } + }, + }; let signature = quote! { #[no_mangle] - pub unsafe extern "C" fn #func_name_ffi ( + pub unsafe extern "C-unwind" fn #func_name_ffi ( __argc: ::byondapi::sys::u4c, __argv: *mut ::byondapi::value::ByondValue ) -> ::byondapi::value::ByondValue @@ -142,7 +152,7 @@ pub fn bind(attr: TokenStream, item: TokenStream) -> TokenStream { } } - fn #func_name(#args) -> ::eyre::Result<::byondapi::value::ByondValue> + fn #func_name(#args) #func_return #body }; result.into() @@ -163,15 +173,25 @@ pub fn bind_raw_args(attr: TokenStream, item: TokenStream) -> TokenStream { let func_name_ffi_disp = quote!(#func_name_ffi).to_string(); //Check for returns - match &input.sig.output { - syn::ReturnType::Default => {} // - - syn::ReturnType::Type(_, ty) => { - return syn::Error::new(ty.span(), "Do not specify the return value of binds") - .to_compile_error() - .into() + let func_return = match &input.sig.output { + syn::ReturnType::Default => { + return syn::Error::new( + input.span(), + "Empty returns are not allowed, please return a Result", + ) + .to_compile_error() + .into() } - } + + syn::ReturnType::Type(_, ty) => match ty.as_ref() { + &syn::Type::Path(_) => &input.sig.output, + _ => { + return syn::Error::new(input.span(), "Invalid return type, please return a Result") + .to_compile_error() + .into() + } + }, + }; if !input.sig.inputs.is_empty() { return syn::Error::new( @@ -184,7 +204,7 @@ pub fn bind_raw_args(attr: TokenStream, item: TokenStream) -> TokenStream { let signature = quote! { #[no_mangle] - pub unsafe extern "C" fn #func_name_ffi ( + pub unsafe extern "C-unwind" fn #func_name_ffi ( __argc: ::byondapi::sys::u4c, __argv: *mut ::byondapi::value::ByondValue ) -> ::byondapi::value::ByondValue @@ -249,7 +269,7 @@ pub fn bind_raw_args(attr: TokenStream, item: TokenStream) -> TokenStream { } } } - fn #func_name(args: &mut [::byondapi::value::ByondValue]) -> ::eyre::Result<::byondapi::value::ByondValue> + fn #func_name(args: &mut [::byondapi::value::ByondValue]) #func_return #body }; result.into() diff --git a/crates/byondapi-rs-test/src/lib.rs b/crates/byondapi-rs-test/src/lib.rs index d8442f3..fbd1ecd 100644 --- a/crates/byondapi-rs-test/src/lib.rs +++ b/crates/byondapi-rs-test/src/lib.rs @@ -1,6 +1,7 @@ #![allow(clippy::missing_safety_doc)] use byondapi::{byond_string, map::*, prelude::*}; +use eyre::Result; #[test] fn generate_binds() { @@ -18,20 +19,20 @@ fn setup_panic_handler() { } #[byondapi::bind] -fn test_connection() { +fn test_connection() -> Result { setup_panic_handler(); Ok(ByondValue::new_num(69.0)) } #[byondapi::bind_raw_args] -fn test_args() { +fn test_args() -> Result { setup_panic_handler(); assert_eq!(args.len(), 2); Ok(args[1]) } #[byondapi::bind] -fn test_ptr(ptr: ByondValue) { +fn test_ptr(ptr: ByondValue) -> Result { setup_panic_handler(); let pointer = ByondValuePointer::new(ptr)?; @@ -44,12 +45,12 @@ fn test_ptr(ptr: ByondValue) { } #[byondapi::bind] -fn test_proc_call(object: ByondValue) { +fn test_proc_call(object: ByondValue) -> Result { Ok(object.call("get_name", &[])?) } #[byondapi::bind] -fn test_readwrite_var(object: ByondValue) { +fn test_readwrite_var(object: ByondValue) -> Result { setup_panic_handler(); object.read_var_id(byond_string!("name"))?.get_string()?; @@ -57,7 +58,7 @@ fn test_readwrite_var(object: ByondValue) { Ok(object.read_string("name")?.try_into()?) } #[byondapi::bind] -fn test_list_push(mut list: ByondValue) { +fn test_list_push(mut list: ByondValue) -> Result { setup_panic_handler(); list.push_list(ByondValue::new_num(8.0))?; @@ -66,7 +67,7 @@ fn test_list_push(mut list: ByondValue) { } #[byondapi::bind] -fn test_list_double(list: ByondValue) { +fn test_list_double(list: ByondValue) -> Result { setup_panic_handler(); let collection = list @@ -78,14 +79,14 @@ fn test_list_double(list: ByondValue) { } #[byondapi::bind] -fn test_list_index(list: ByondValue) { +fn test_list_index(list: ByondValue) -> Result { setup_panic_handler(); Ok(list.read_list_index(3.0)?) } #[byondapi::bind] -fn test_list_pop(mut list: ByondValue) { +fn test_list_pop(mut list: ByondValue) -> Result { setup_panic_handler(); let element = list.pop_list()?; @@ -98,13 +99,13 @@ fn test_list_pop(mut list: ByondValue) { } #[byondapi::bind] -fn test_length_with_list(list: ByondValue) { +fn test_length_with_list(list: ByondValue) -> Result { setup_panic_handler(); Ok(list.builtin_length()?) } #[byondapi::bind] -fn test_block() { +fn test_block() -> Result { setup_panic_handler(); let block = byond_block( @@ -123,13 +124,13 @@ fn test_block() { } #[byondapi::bind] -fn test_length_with_str(object: ByondValue) { +fn test_length_with_str(object: ByondValue) -> Result { setup_panic_handler(); Ok(object.builtin_length()?) } #[byondapi::bind] -fn test_list_key_lookup(mut list: ByondValue) { +fn test_list_key_lookup(mut list: ByondValue) -> Result { setup_panic_handler(); let num: f32 = list.read_list_index("cat")?.try_into()?; @@ -165,7 +166,7 @@ fn test_list_key_lookup(mut list: ByondValue) { } #[byondapi::bind] -fn test_ref(turf: ByondValue) { +fn test_ref(turf: ByondValue) -> Result { setup_panic_handler(); let turf_type = turf.get_type(); @@ -177,7 +178,7 @@ fn test_ref(turf: ByondValue) { } #[byondapi::bind] -fn test_non_assoc_list(list: ByondValue) { +fn test_non_assoc_list(list: ByondValue) -> Result { setup_panic_handler(); let map = list @@ -199,7 +200,7 @@ fn test_non_assoc_list(list: ByondValue) { } #[byondapi::bind] -fn test_list_read(list: ByondValue) { +fn test_list_read(list: ByondValue) -> Result { setup_panic_handler(); let map = list.get_list_values()?; @@ -217,7 +218,7 @@ fn test_list_read(list: ByondValue) { } #[byondapi::bind] -fn test_new_obj() { +fn test_new_obj() -> Result { Ok(ByondValue::builtin_new( ByondValue::try_from("/datum/testobject")?, &[], diff --git a/crates/byondapi-rs/src/lib.rs b/crates/byondapi-rs/src/lib.rs index 65d053a..b9e0e26 100644 --- a/crates/byondapi-rs/src/lib.rs +++ b/crates/byondapi-rs/src/lib.rs @@ -19,6 +19,7 @@ pub mod binds; pub mod byond_string; pub mod global_call; pub mod prelude; +pub mod threadsync; pub mod value; use crate::value::ByondValue; diff --git a/crates/byondapi-rs/src/threadsync.rs b/crates/byondapi-rs/src/threadsync.rs new file mode 100644 index 0000000..abdc15e --- /dev/null +++ b/crates/byondapi-rs/src/threadsync.rs @@ -0,0 +1,25 @@ +use crate::static_global::byond; +use crate::value::ByondValue; +use byondapi_sys::CByondValue; +use std::os::raw::c_void; + +struct CallbackData ByondValue + Send> { + callback: Option, +} + +extern "C" fn trampoline ByondValue + Send>(data: *mut c_void) -> CByondValue { + let data = unsafe { Box::from_raw(data as *mut CallbackData) }; + (data.callback.unwrap())().into_inner() +} + +pub fn thread_sync(callback: F, block: bool) -> ByondValue +where + F: FnOnce() -> ByondValue + Send + 'static, +{ + let data = Box::new(CallbackData { + callback: Some(callback), + }); + let data_ptr = Box::into_raw(data) as *mut c_void; + + ByondValue(unsafe { byond().Byond_ThreadSync(Some(trampoline::), data_ptr, block) }) +}