Skip to content

Commit

Permalink
A much better solution to rust-lang/rust#121408: add a dummy variant …
Browse files Browse the repository at this point in the history
…to the DispatchRock union so that it won't be considered a singleton union
  • Loading branch information
curiousdannii committed Mar 5, 2024
1 parent c8d0354 commit eae4af5
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 102 deletions.
20 changes: 5 additions & 15 deletions remglk/src/glkapi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ mod windows;

use std::cmp::min;
use std::mem;
use mem::MaybeUninit;
use std::ops::DerefMut;
use std::str;
use std::time::SystemTime;
Expand Down Expand Up @@ -1564,24 +1563,16 @@ where S: Default + GlkSystem {

pub fn retain_array(&self, buf: &GlkBuffer) -> DispatchRock {
match buf {
GlkBuffer::U8(buf) => {
let mut disprock: MaybeUninit<DispatchRock> = MaybeUninit::uninit();
(self.retain_array_callbacks_u8.as_ref().unwrap().retain)(buf.as_ptr(), buf.len() as u32, "&+#!Cn".as_ptr(), disprock.as_mut_ptr());
unsafe {disprock.assume_init()}
},
GlkBuffer::U32(buf) => {
let mut disprock: MaybeUninit<DispatchRock> = MaybeUninit::uninit();
(self.retain_array_callbacks_u32.as_ref().unwrap().retain)(buf.as_ptr(), buf.len() as u32, "&+#!Iu".as_ptr(), disprock.as_mut_ptr());
unsafe {disprock.assume_init()}
},
GlkBuffer::U8(buf) => (self.retain_array_callbacks_u8.as_ref().unwrap().retain)(buf.as_ptr(), buf.len() as u32, b"&+#!Cn\0".as_ptr()),
GlkBuffer::U32(buf) => (self.retain_array_callbacks_u32.as_ref().unwrap().retain)(buf.as_ptr(), buf.len() as u32, b"&+#!Iu\0".as_ptr()),
}
}

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),
GlkOwnedBuffer::U32(buf) => (self.retain_array_callbacks_u32.as_ref().unwrap().unretain)(Box::leak(buf).as_ptr(), len, "&+#!Iu".as_ptr(), disprock),
GlkOwnedBuffer::U8(buf) => (self.retain_array_callbacks_u8.as_ref().unwrap().unretain)(Box::leak(buf).as_ptr(), len, b"&+#!Cn\0".as_ptr(), disprock),
GlkOwnedBuffer::U32(buf) => (self.retain_array_callbacks_u32.as_ref().unwrap().unretain)(Box::leak(buf).as_ptr(), len, b"&+#!Iu\0".as_ptr(), disprock),
};
}
}
Expand Down Expand Up @@ -1618,8 +1609,7 @@ pub struct GlkDate {
}

// Retained array callbacks
// The WASM ABI means that we can't return a DispatchRock, so it must be set through an out parameter
pub type RetainArrayCallback<T> = extern fn(*const T, u32, *const u8, *mut DispatchRock);
pub type RetainArrayCallback<T> = extern fn(*const T, u32, *const u8) -> DispatchRock;
pub type UnretainArrayCallback<T> = extern fn(*const T, u32, *const u8, DispatchRock);

pub struct RetainArrayCallbacks<T> {
Expand Down
18 changes: 6 additions & 12 deletions remglk/src/glkapi/objects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ https://github.com/curiousdannii/remglk-rs
*/

use std::mem::MaybeUninit;
use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Mutex, Weak};

Expand Down Expand Up @@ -129,8 +128,8 @@ where T: Default + GlkObjectClass, GlkObject<T>: Default + Eq {
obj.id = self.counter;
obj.rock = rock;
self.counter += 1;
if let Some(_) = self.register_cb {
obj.disprock = Some(self.register_callback(obj_ptr, self.object_class));
if let Some(register_cb) = self.register_cb {
obj.disprock = Some(register_cb(obj_ptr, self.object_class));
}
match self.first.as_ref() {
None => {
Expand All @@ -148,19 +147,13 @@ where T: Default + GlkObjectClass, GlkObject<T>: Default + Eq {
};
}

fn register_callback(&self, obj_ptr: *const Mutex<GlkObjectMetadata<T>>, object_class: u32) -> DispatchRock {
let mut disprock: MaybeUninit<DispatchRock> = MaybeUninit::uninit();
self.register_cb.unwrap()(obj_ptr, object_class, disprock.as_mut_ptr());
unsafe {disprock.assume_init()}
}

pub fn set_callbacks(&mut self, register_cb: DispatchRegisterCallback<T>, unregister_cb: DispatchUnregisterCallback<T>) {
self.register_cb = Some(register_cb);
self.unregister_cb = Some(unregister_cb);
for obj in self.store.iter() {
let obj_ptr = obj.as_ptr();
let mut obj = obj.lock().unwrap();
obj.disprock = Some(self.register_callback(obj_ptr, self.object_class));
obj.disprock = Some(register_cb(obj_ptr, self.object_class));
}
}

Expand Down Expand Up @@ -258,10 +251,11 @@ pub struct DispatchRockPtr {
pub union DispatchRock {
num: u32,
ptr: *const DispatchRockPtr,
// Add a u64 dummy variant to work around https://github.com/rust-lang/rust/issues/121408
dummy_variant: u64,
}

// The WASM ABI means that we can't return a DispatchRock, so it must be set through an out parameter
pub type DispatchRegisterCallback<T> = fn(*const Mutex<GlkObjectMetadata<T>>, u32, *mut DispatchRock);
pub type DispatchRegisterCallback<T> = fn(*const Mutex<GlkObjectMetadata<T>>, u32) -> DispatchRock;
pub type DispatchUnregisterCallback<T> = fn(*const Mutex<GlkObjectMetadata<T>>, u32, DispatchRock);

pub trait GlkObjectClass {
Expand Down
23 changes: 10 additions & 13 deletions remglk_capi/src/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,11 @@ use super::*;
use common::*;
use glkapi::*;

// The WASM ABI means that we can't return a DispatchRock, so it must be set through an out parameter
type RegisterCallbackGeneric = extern fn(*const c_void, u32, *mut DispatchRock);
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_rs(register_cb: RegisterCallbackGeneric, unregister_cb: UnregisterCallbackGeneric) {
pub unsafe extern "C" fn gidispatch_set_object_registry(register_cb: RegisterCallbackGeneric, unregister_cb: UnregisterCallbackGeneric) {
let mut glkapi = glkapi().lock().unwrap();
let register = mem::transmute::<RegisterCallbackGeneric, DispatchRegisterCallback<FileRef>>(register_cb);
let unregister = mem::transmute::<UnregisterCallbackGeneric, DispatchUnregisterCallback<FileRef>>(unregister_cb);
Expand All @@ -38,34 +37,32 @@ pub unsafe extern "C" fn gidispatch_set_object_registry_rs(register_cb: Register
}

// 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, dispatchrock_ptr: *mut DispatchRock) {
pub extern "C" fn gidispatch_get_objrock_fileref(ptr: FileRefPtr) -> DispatchRock {
let obj = from_ptr(ptr);
let obj = obj.lock().unwrap();
write_ptr(dispatchrock_ptr, obj.disprock.unwrap());
obj.disprock.unwrap()
}

#[no_mangle]
pub extern "C" fn gidispatch_get_objrock_stream(ptr: StreamPtr, dispatchrock_ptr: *mut DispatchRock) {
pub extern "C" fn gidispatch_get_objrock_stream(ptr: StreamPtr) -> DispatchRock {
let obj = from_ptr(ptr);
let obj = obj.lock().unwrap();
write_ptr(dispatchrock_ptr, obj.disprock.unwrap());
obj.disprock.unwrap()
}

#[no_mangle]
pub extern "C" fn gidispatch_get_objrock_window(ptr: WindowPtr, dispatchrock_ptr: *mut DispatchRock) {
pub extern "C" fn gidispatch_get_objrock_window(ptr: WindowPtr) -> DispatchRock {
let obj = from_ptr(ptr);
let obj = obj.lock().unwrap();
write_ptr(dispatchrock_ptr, obj.disprock.unwrap());
obj.disprock.unwrap()
}

// The WASM ABI means that we can't return a DispatchRock, so it must be set through an out parameter
type RetainArrayCallbackGeneric = extern fn(*const c_void, u32, *const c_char, *mut DispatchRock);
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_rs(register_cb: RetainArrayCallbackGeneric, unregister_cb: UnretainArrayCallbackGeneric) {
pub unsafe extern "C" fn gidispatch_set_retained_registry(register_cb: RetainArrayCallbackGeneric, unregister_cb: UnretainArrayCallbackGeneric) {
let mut glkapi = glkapi().lock().unwrap();
let retain = mem::transmute::<RetainArrayCallbackGeneric, RetainArrayCallback<u8>>(register_cb);
let unretain = mem::transmute::<UnretainArrayCallbackGeneric, UnretainArrayCallback<u8>>(unregister_cb);
Expand Down
38 changes: 3 additions & 35 deletions remglk_capi/src/glk/support.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,51 +13,19 @@ MIT licenced
#include "glk.h"
#include "support.h"

gidispatch_rock_t (*gli_register_arr)(void *array, glui32 len, char *typecode) = NULL;
gidispatch_rock_t (*gli_register_obj)(void *obj, glui32 objclass) = NULL;

gidispatch_rock_t gidispatch_get_objrock(void *obj, glui32 objclass) {
gidispatch_rock_t rock;
switch (objclass) {
case gidisp_Class_Fileref:
gidispatch_get_objrock_fileref(obj, &rock);
return rock;
return gidispatch_get_objrock_fileref(obj);
case gidisp_Class_Stream:
gidispatch_get_objrock_stream(obj, &rock);
return rock;
return gidispatch_get_objrock_stream(obj);
case gidisp_Class_Window:
gidispatch_get_objrock_window(obj, &rock);
return rock;
return gidispatch_get_objrock_window(obj);
default:
__builtin_unreachable();
}
}

// Because of a WASM ABI issue, we call the VM's registry functions indirectly
void gidispatch_call_array_register(void *array, glui32 len, char *typecode, gidispatch_rock_t *rock_ptr) {
gidispatch_rock_t rock = gli_register_arr(array, len, typecode);
*rock_ptr = rock;
}
void gidispatch_call_object_register(void *obj, glui32 objclass, gidispatch_rock_t *rock_ptr) {
gidispatch_rock_t rock = gli_register_obj(obj, objclass);
*rock_ptr = rock;
}

void gidispatch_set_object_registry(
gidispatch_rock_t (*regi)(void *obj, glui32 objclass),
void (*unregi)(void *obj, glui32 objclass, gidispatch_rock_t objrock))
{
gli_register_obj = regi;
gidispatch_set_object_registry_rs(gidispatch_call_object_register, unregi);
}
void gidispatch_set_retained_registry(
gidispatch_rock_t (*regi)(void *array, glui32 len, char *typecode),
void (*unregi)(void *array, glui32 len, char *typecode, gidispatch_rock_t objrock))
{
gli_register_arr = regi;
gidispatch_set_retained_registry_rs(gidispatch_call_array_register, unregi);
}

glkunix_argumentlist_t *glkunix_arguments_addr(void) {
return glkunix_arguments;
}
12 changes: 3 additions & 9 deletions remglk_capi/src/glk/support.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,8 @@
#include "gi_dispa.h"
#include "glkstart.h"

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);
extern void gidispatch_set_object_registry_rs(
void (*regi)(void *obj, glui32 objclass, gidispatch_rock_t *rock_ptr),
void (*unregi)(void *obj, glui32 objclass, gidispatch_rock_t objrock));
extern void gidispatch_set_retained_registry_rs(
void (*regi)(void *array, glui32 len, char *typecode, gidispatch_rock_t *rock_ptr),
void (*unregi)(void *array, glui32 len, char *typecode, gidispatch_rock_t objrock));
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);

#endif /* REMGLK_RS_SUPPORT_START_H */
36 changes: 18 additions & 18 deletions remglk_capi/src/systems/emglken.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ https://github.com/curiousdannii/remglk-rs
*/

use std::collections::HashMap;
use std::ptr;
use std::mem::MaybeUninit;
use std::slice;

use super::*;
Expand All @@ -19,8 +19,9 @@ use glkapi::protocol::{Event, SystemFileRef, Update};

extern "C" {
fn emglken_fileref_exists(filename_ptr: *const u8, filename_len: usize) -> bool;
fn emglken_fileref_read(filename_ptr: *const u8, filename_len: usize, buffer: &mut EmglkenBuffer) -> bool;
fn emglken_get_glkote_event(buffer: &mut EmglkenBuffer);
fn emglken_fileref_read(filename_ptr: *const u8, filename_len: usize, buffer: *mut EmglkenBuffer) -> bool;
fn emglken_get_glkote_event(buffer: *mut EmglkenBuffer);
fn emglken_send_glkote_update(update_ptr: *const u8, update_len: usize);
}

#[repr(C)]
Expand Down Expand Up @@ -67,13 +68,10 @@ impl GlkSystem for EmglkenSystem {
Some(buf.clone())
}
else {
let mut buf = EmglkenBuffer {
ptr: ptr::null_mut(),
len: 0,
};
let result = unsafe {emglken_fileref_read(fileref.filename.as_ptr(), fileref.filename.len(), &mut buf)};
let mut buf: MaybeUninit<EmglkenBuffer> = MaybeUninit::uninit();
let result = unsafe {emglken_fileref_read(fileref.filename.as_ptr(), fileref.filename.len(), buf.as_mut_ptr())};
if result {
return Some(buffer_to_boxed_slice(&buf));
return Some(buffer_to_boxed_slice(&unsafe {buf.assume_init()}));
}
None
}
Expand All @@ -88,22 +86,24 @@ impl GlkSystem for EmglkenSystem {
}

fn flush_writeable_files(&mut self) {
unimplemented!()
for (_filename, _buf) in self.cache.drain() {
unimplemented!()
}
self.cache.shrink_to(4);
}

fn get_glkote_event(&mut self) -> Option<Event> {
let mut buf = EmglkenBuffer {
ptr: ptr::null_mut(),
len: 0,
};
unsafe {emglken_get_glkote_event(&mut buf)};
let data = buffer_to_boxed_slice(&buf);
let mut buf: MaybeUninit<EmglkenBuffer> = MaybeUninit::uninit();
unsafe {emglken_get_glkote_event(buf.as_mut_ptr())};
let data = buffer_to_boxed_slice(&unsafe {buf.assume_init()});
let event: Event = serde_json::from_slice(&data).unwrap();
return Some(event);
}

fn send_glkote_update(&mut self, _update: Update) {
unimplemented!()
fn send_glkote_update(&mut self, update: Update) {
// Send the update
let output = serde_json::to_string(&update).unwrap();
unsafe {emglken_send_glkote_update(output.as_ptr(), output.len())};
}
}

Expand Down
7 changes: 7 additions & 0 deletions remglk_capi/src/systems/library_emglken.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ addToLibrary({
})
},

emglken_send_glkote_update(update_ptr, update_len) {
const update = UTF8ToString(update_ptr, update_len)
const obj = JSON.parse(update)
// TODO: Store the usage of a fileref prompt request?
GlkOte.update(obj)
},

$writeBuffer(buffer, data) {
const ptr = _malloc(data.length)
HEAP8.set(data, ptr)
Expand Down

0 comments on commit eae4af5

Please sign in to comment.