From 33318d9cb8b9022982dc3c4aa88eb449b03e3ba3 Mon Sep 17 00:00:00 2001 From: Dannii Willis Date: Wed, 21 Feb 2024 10:52:19 +1000 Subject: [PATCH] Making some progress integrating Remglk-rs into Emglken. DispatchRock has to be a union, and because of the WASM ABI, it can't be returned from functions --- Cargo.toml | 10 ++++++- remglk/src/glkapi/mod.rs | 46 +++++++++++++++++++---------- remglk/src/glkapi/objects.rs | 18 +++++++---- remglk/src/lib.rs | 2 +- remglk_capi/Cargo.toml | 4 +-- remglk_capi/src/dispatch.rs | 21 ++++++------- remglk_capi/src/glk/support.c | 12 ++++++-- remglk_capi/src/glk/support.h | 6 ++-- remglk_capi/src/systems/emglken.rs | 23 ++++++--------- remglk_capi/src/systems/standard.rs | 6 ++-- 10 files changed, 90 insertions(+), 58 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3c90363..eae91b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,4 +7,12 @@ members = [ resolver = "2" [profile.release] -lto = true \ No newline at end of file +lto = true + +[profile.dev-wasm] +inherits = "dev" +panic = "abort" + +[profile.release-wasm] +inherits = "release" +panic = "abort" \ No newline at end of file diff --git a/remglk/src/glkapi/mod.rs b/remglk/src/glkapi/mod.rs index 631be32..51e50f4 100644 --- a/remglk/src/glkapi/mod.rs +++ b/remglk/src/glkapi/mod.rs @@ -213,13 +213,18 @@ where S: Default + GlkSystem { let update = self.update(); self.system.send_glkote_update(update); let event = self.system.get_glkote_event(); - let res = self.handle_event(event)?; - if let Some(fref) = res.fref { - let (filename, fref) = match fref { - FileRefResponse::String(filename) => (filename, None), - FileRefResponse::Fref(fref) => (fref.filename.clone(), Some(fref)), - }; - return Ok(Some(self.create_fileref(filename, rock, usage, fref))); + if let Some(event) = event { + let res = self.handle_event(event)?; + if let Some(fref) = res.fref { + let (filename, fref) = match fref { + FileRefResponse::String(filename) => (filename, None), + FileRefResponse::Fref(fref) => (fref.filename.clone(), Some(fref)), + }; + return Ok(Some(self.create_fileref(filename, rock, usage, fref))); + } + } + else { + self.glk_exit(); } Ok(None) } @@ -455,7 +460,13 @@ where S: Default + GlkSystem { let update = self.update(); self.system.send_glkote_update(update); let event = self.system.get_glkote_event(); - self.handle_event(event) + if let Some(event) = event { + self.handle_event(event) + } + else { + self.glk_exit(); + Ok(GlkEvent::default()) + } } pub fn glk_select_poll(&mut self) -> GlkEvent { @@ -1019,7 +1030,12 @@ where S: Default + GlkSystem { pub fn get_glkote_init(&mut self) { let event = self.system.get_glkote_event(); - self.handle_event(event).unwrap(); + if let Some(event) = event { + self.handle_event(event).unwrap(); + } + else { + self.glk_exit(); + } } pub fn handle_event(&mut self, mut event: Event) -> GlkResult { @@ -1257,7 +1273,7 @@ where S: Default + GlkSystem { Ok(Some(str)) } - fn create_memory_stream(&mut self, buf: Box<[T]>, fmode: FileMode, rock: u32, disprock: Option) -> GlkResult + fn create_memory_stream(&mut self, buf: Box<[T]>, fmode: FileMode, rock: u32, disprock: Option) -> GlkResult where Stream: From> { if fmode == FileMode::WriteAppend { return Err(IllegalFilemode); @@ -1545,14 +1561,14 @@ where S: Default + GlkSystem { Ok(()) } - pub fn retain_array(&self, buf: &GlkBuffer) -> DispatchRockPtr { + pub fn retain_array(&self, buf: &GlkBuffer) -> DispatchRock { match buf { GlkBuffer::U8(buf) => (self.retain_array_callbacks_u8.as_ref().unwrap().retain)(buf.as_ptr(), buf.len() as u32, "&+#!Cn".as_ptr()), GlkBuffer::U32(buf) => (self.retain_array_callbacks_u32.as_ref().unwrap().retain)(buf.as_ptr(), buf.len() as u32, "&+#!Iu".as_ptr()), } } - pub fn unretain_array(&self, buf: GlkOwnedBuffer, disprock: DispatchRockPtr) { + pub fn unretain_array(&self, buf: GlkOwnedBuffer, disprock: DispatchRock) { let len = buf.len() as u32; match buf { GlkOwnedBuffer::U8(buf) => (self.retain_array_callbacks_u8.as_ref().unwrap().unretain)(Box::leak(buf).as_ptr(), len, "&+#!Cn".as_ptr(), disprock), @@ -1593,8 +1609,8 @@ pub struct GlkDate { } // Retained array callbacks -pub type RetainArrayCallback = extern fn(*const T, u32, *const u8) -> DispatchRockPtr; -pub type UnretainArrayCallback = extern fn(*const T, u32, *const u8, DispatchRockPtr); +pub type RetainArrayCallback = extern fn(*const T, u32, *const u8) -> DispatchRock; +pub type UnretainArrayCallback = extern fn(*const T, u32, *const u8, DispatchRock); pub struct RetainArrayCallbacks { pub retain: RetainArrayCallback, @@ -1708,7 +1724,7 @@ fn glkdate_to_datetime(timezone: T, date: &GlkDate) -> DateTime normalised_date = normalised_date.checked_add_months(chrono::Months::new(months as u32)).unwrap(); } if months < 0 { - normalised_date = normalised_date.checked_sub_months(chrono::Months::new(months as u32)).unwrap(); + normalised_date = normalised_date.checked_sub_months(chrono::Months::new((-months) as u32)).unwrap(); } let mut normalised_date = NaiveDateTime::from(normalised_date).and_utc(); let duration = Duration::days(date.day as i64 - 1) diff --git a/remglk/src/glkapi/objects.rs b/remglk/src/glkapi/objects.rs index 761cd2f..3f1fbc6 100644 --- a/remglk/src/glkapi/objects.rs +++ b/remglk/src/glkapi/objects.rs @@ -196,8 +196,8 @@ where T: Default + GlkObjectClass, GlkObject: Default + Eq { /** Contains the private metadata we keep in each object store */ #[derive(Default)] pub struct GlkObjectMetadata { - pub array_disprock: Option, - pub disprock: Option, + pub array_disprock: Option, + pub disprock: Option, /** The ID, used in the GlkOte protocol */ pub id: u32, obj: T, @@ -241,14 +241,20 @@ impl DerefMut for GlkObjectMetadata { /** A dispatch rock, which could be anything (*not* the same as a normal Glk rock) */ // See for explanation https://stackoverflow.com/a/38315613/2854284 #[repr(C)] -pub struct DispatchRock { +pub struct DispatchRockPtr { _data: [u8; 0], _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>, } -pub type DispatchRockPtr = *const DispatchRock; -pub type DispatchRegisterCallback = fn(*const Mutex>, u32) -> DispatchRockPtr; -pub type DispatchUnregisterCallback = fn(*const Mutex>, u32, DispatchRockPtr); +#[derive(Clone, Copy)] +#[repr(C)] +pub union DispatchRock { + num: u32, + ptr: *const DispatchRockPtr, +} + +pub type DispatchRegisterCallback = fn(*const Mutex>, u32) -> DispatchRock; +pub type DispatchUnregisterCallback = fn(*const Mutex>, u32, DispatchRock); pub trait GlkObjectClass { fn get_object_class_id() -> u32; diff --git a/remglk/src/lib.rs b/remglk/src/lib.rs index 8b40dc7..c1c0fd1 100644 --- a/remglk/src/lib.rs +++ b/remglk/src/lib.rs @@ -29,5 +29,5 @@ pub trait GlkSystem { /** Send an update to GlkOte */ fn send_glkote_update(&mut self, update: Update); /** Get an event from GlkOte */ - fn get_glkote_event(&mut self) -> Event; + fn get_glkote_event(&mut self) -> Option; } \ No newline at end of file diff --git a/remglk_capi/Cargo.toml b/remglk_capi/Cargo.toml index daef59c..60bded0 100644 --- a/remglk_capi/Cargo.toml +++ b/remglk_capi/Cargo.toml @@ -17,12 +17,12 @@ crate-type=["staticlib"] [dependencies] remglk = {path = "../remglk", version = "0.1.0"} -serde = {version = "1.0"} +serde = "1.0" serde_json = "1.0" thiserror = "1.0.40" widestring = "1.0.2" -[target.'cfg(emscripten)'.dependencies] +[target.'cfg(target_os = "emscripten")'.dependencies] emscripten_em_js = {path = "../emscripten_em_js", version = "0.1.0"} [build-dependencies] diff --git a/remglk_capi/src/dispatch.rs b/remglk_capi/src/dispatch.rs index 0fc9952..64a2450 100644 --- a/remglk_capi/src/dispatch.rs +++ b/remglk_capi/src/dispatch.rs @@ -19,8 +19,8 @@ use super::*; use common::*; use glkapi::*; -type RegisterCallbackGeneric = extern fn(*const c_void, u32) -> DispatchRockPtr; -type UnregisterCallbackGeneric = extern fn(*const c_void, u32, DispatchRockPtr); +type RegisterCallbackGeneric = extern fn(*const c_void, u32) -> DispatchRock; +type UnregisterCallbackGeneric = extern fn(*const c_void, u32, DispatchRock); #[no_mangle] pub unsafe extern "C" fn gidispatch_set_object_registry(register_cb: RegisterCallbackGeneric, unregister_cb: UnregisterCallbackGeneric) { @@ -37,29 +37,30 @@ pub unsafe extern "C" fn gidispatch_set_object_registry(register_cb: RegisterCal } // The C function `gidispatch_get_objrock` takes a generic pointer, which we can't really deal with here in Rust, so support.c will handle calling the appropriate function +// The WASM ABI means that we can't return a DispatchRock, so it must be set through an out parameter #[no_mangle] -pub extern "C" fn gidispatch_get_objrock_fileref(ptr: FileRefPtr) -> DispatchRockPtr { +pub extern "C" fn gidispatch_get_objrock_fileref(ptr: FileRefPtr, dispatchrock_ptr: *mut DispatchRock) { let obj = from_ptr(ptr); let obj = obj.lock().unwrap(); - obj.disprock.unwrap() + write_ptr(dispatchrock_ptr, obj.disprock.unwrap()); } #[no_mangle] -pub extern "C" fn gidispatch_get_objrock_stream(ptr: StreamPtr) -> DispatchRockPtr { +pub extern "C" fn gidispatch_get_objrock_stream(ptr: StreamPtr, dispatchrock_ptr: *mut DispatchRock) { let obj = from_ptr(ptr); let obj = obj.lock().unwrap(); - obj.disprock.unwrap() + write_ptr(dispatchrock_ptr, obj.disprock.unwrap()); } #[no_mangle] -pub extern "C" fn gidispatch_get_objrock_window(ptr: WindowPtr) -> DispatchRockPtr { +pub extern "C" fn gidispatch_get_objrock_window(ptr: WindowPtr, dispatchrock_ptr: *mut DispatchRock) { let obj = from_ptr(ptr); let obj = obj.lock().unwrap(); - obj.disprock.unwrap() + write_ptr(dispatchrock_ptr, obj.disprock.unwrap()); } -type RetainArrayCallbackGeneric = extern fn(*const c_void, u32, *const c_char) -> DispatchRockPtr; -type UnretainArrayCallbackGeneric = extern fn(*const c_void, u32, *const c_char, DispatchRockPtr); +type RetainArrayCallbackGeneric = extern fn(*const c_void, u32, *const c_char) -> DispatchRock; +type UnretainArrayCallbackGeneric = extern fn(*const c_void, u32, *const c_char, DispatchRock); #[no_mangle] pub unsafe extern "C" fn gidispatch_set_retained_registry(register_cb: RetainArrayCallbackGeneric, unregister_cb: UnretainArrayCallbackGeneric) { diff --git a/remglk_capi/src/glk/support.c b/remglk_capi/src/glk/support.c index e4d2e62..e18d06a 100644 --- a/remglk_capi/src/glk/support.c +++ b/remglk_capi/src/glk/support.c @@ -14,13 +14,19 @@ MIT licenced #include "support.h" gidispatch_rock_t gidispatch_get_objrock(void *obj, glui32 objclass) { + gidispatch_rock_t rock; switch (objclass) { case gidisp_Class_Fileref: - return gidispatch_get_objrock_fileref(obj); + gidispatch_get_objrock_fileref(obj, &rock); + return rock; case gidisp_Class_Stream: - return gidispatch_get_objrock_stream(obj); + gidispatch_get_objrock_stream(obj, &rock); + return rock; case gidisp_Class_Window: - return gidispatch_get_objrock_window(obj); + gidispatch_get_objrock_window(obj, &rock); + return rock; + default: + __builtin_unreachable(); } } diff --git a/remglk_capi/src/glk/support.h b/remglk_capi/src/glk/support.h index b49b84b..e1a3f38 100644 --- a/remglk_capi/src/glk/support.h +++ b/remglk_capi/src/glk/support.h @@ -4,9 +4,9 @@ #include "gi_dispa.h" #include "glkstart.h" -extern gidispatch_rock_t gidispatch_get_objrock_fileref(void *obj); -extern gidispatch_rock_t gidispatch_get_objrock_stream(void *obj); -extern gidispatch_rock_t gidispatch_get_objrock_window(void *obj); +extern void gidispatch_get_objrock_fileref(void *obj, gidispatch_rock_t *rock_ptr); +extern void gidispatch_get_objrock_stream(void *obj, gidispatch_rock_t *rock_ptr); +extern void gidispatch_get_objrock_window(void *obj, gidispatch_rock_t *rock_ptr); glkunix_argumentlist_t *glkunix_arguments_addr(void); diff --git a/remglk_capi/src/systems/emglken.rs b/remglk_capi/src/systems/emglken.rs index eb43c14..19ac4ac 100644 --- a/remglk_capi/src/systems/emglken.rs +++ b/remglk_capi/src/systems/emglken.rs @@ -10,12 +10,8 @@ https://github.com/curiousdannii/remglk-rs */ use std::collections::HashMap; -use std::env::temp_dir; -use std::fs; -use std::io::{self, BufRead}; -use std::path::Path; -use emscripten_em_js::em_js; +//use emscripten_em_js::em_js; use super::*; use remglk::GlkSystem; @@ -32,8 +28,7 @@ pub fn glkapi() -> &'static Mutex { #[derive(Default)] pub struct EmglkenSystem { - cache: HashMap>, - tempfile_counter: u32, + _cache: HashMap>, } impl GlkSystem for EmglkenSystem { @@ -46,23 +41,23 @@ impl GlkSystem for EmglkenSystem { } } - fn fileref_delete(&mut self, fileref: &SystemFileRef) { + fn fileref_delete(&mut self, _fileref: &SystemFileRef) { unimplemented!() } - fn fileref_exists(&mut self, fileref: &SystemFileRef) -> bool { + fn fileref_exists(&mut self, _fileref: &SystemFileRef) -> bool { unimplemented!() } - fn fileref_read(&mut self, fileref: &SystemFileRef) -> Option> { + fn fileref_read(&mut self, _fileref: &SystemFileRef) -> Option> { unimplemented!() } - fn fileref_temporary(&mut self, filetype: FileType) -> SystemFileRef { + fn fileref_temporary(&mut self, _filetype: FileType) -> SystemFileRef { unimplemented!() } - fn fileref_write_buffer(&mut self, fileref: &SystemFileRef, buf: Box<[u8]>) { + fn fileref_write_buffer(&mut self, _fileref: &SystemFileRef, _buf: Box<[u8]>) { unimplemented!() } @@ -70,11 +65,11 @@ impl GlkSystem for EmglkenSystem { unimplemented!() } - fn get_glkote_event(&mut self) -> Event { + fn get_glkote_event(&mut self) -> Option { unimplemented!() } - fn send_glkote_update(&mut self, update: Update) { + fn send_glkote_update(&mut self, _update: Update) { unimplemented!() } } \ No newline at end of file diff --git a/remglk_capi/src/systems/standard.rs b/remglk_capi/src/systems/standard.rs index 2de8d2f..7aa8654 100644 --- a/remglk_capi/src/systems/standard.rs +++ b/remglk_capi/src/systems/standard.rs @@ -85,7 +85,7 @@ impl GlkSystem for StandardSystem { self.cache.shrink_to(4); } - fn get_glkote_event(&mut self) -> Event { + fn get_glkote_event(&mut self) -> Option { // Read a line from stdin let stdin = io::stdin(); for line in stdin.lock().lines() { @@ -94,9 +94,9 @@ impl GlkSystem for StandardSystem { continue; } let event: Event = serde_json::from_str(&data).unwrap(); - return event; + return Some(event); } - unreachable!() + None } fn send_glkote_update(&mut self, update: Update) {