furiouzz
furiouzz5mo ago

How to send an enum value from Rust to Deno

Hello there 👋 I am quite a beginner to FFI and I am not sure which resources to read to learn more about it in Rust. My problem: I got two enums MyEvent and MySubEvent.
#[repr(C)]
pub enum MySubEvent {
X,
Y(f64),
}

#[repr(C)]
pub enum MyEvent {
Event(f64, f64),
SubEvent(MySubEvent),
Nothing,
}
#[repr(C)]
pub enum MySubEvent {
X,
Y(f64),
}

#[repr(C)]
pub enum MyEvent {
Event(f64, f64),
SubEvent(MySubEvent),
Nothing,
}
I want to emit these events to callback function declared in Deno side
#[no_mangle]
pub extern "C" fn run_event_loop(func: Option<extern "C" fn(MyEvent)>) {
let callback = func.unwrap();
callback(MyEvent::Event(0., 36.));
callback(MyEvent::SubEvent(MySubEvent::X));
callback(MyEvent::SubEvent(MySubEvent::Y(1.0)));
callback(MyEvent::Nothing);
}
#[no_mangle]
pub extern "C" fn run_event_loop(func: Option<extern "C" fn(MyEvent)>) {
let callback = func.unwrap();
callback(MyEvent::Event(0., 36.));
callback(MyEvent::SubEvent(MySubEvent::X));
callback(MyEvent::SubEvent(MySubEvent::Y(1.0)));
callback(MyEvent::Nothing);
}
I do not know how to recognize which event has been sent in Deno
const onEvent = new Deno.UnsafeCallback(
{
parameters: ["pointer"],
result: "void",
},
(e) => {
if (e === null) return;
const view = new Deno.UnsafePointerView(e);
const eventType = view.getUint32(); // Is it the right way to do it?
console.log(eventType);
}
);

const lib = Deno.dlopen("./target/debug/mylib.dylib", {
run_event_loop: { parameters: ["function"], result: "void" },
});

lib.symbols.run_event_loop(onEvent.pointer);
lib.close();
const onEvent = new Deno.UnsafeCallback(
{
parameters: ["pointer"],
result: "void",
},
(e) => {
if (e === null) return;
const view = new Deno.UnsafePointerView(e);
const eventType = view.getUint32(); // Is it the right way to do it?
console.log(eventType);
}
);

const lib = Deno.dlopen("./target/debug/mylib.dylib", {
run_event_loop: { parameters: ["function"], result: "void" },
});

lib.symbols.run_event_loop(onEvent.pointer);
lib.close();
5 Replies
Deno AI Helper
Deno AI Helper5mo ago
Based on the documentation, Deno's FFI API currently supports a list of types that can be used to communicate between Deno and native libraries. However, complex types like enums are not directly supported. In your case, you are trying to pass an enum from Rust to Deno. This is not directly supported by Deno's FFI API. The types that are currently supported by Deno's FFI API are i8, u8, i16, u16, i32, u32, i64, u64, usize, f32, f64, void, pointer, buffer, function, and { struct: [...] }. One possible workaround could be to represent your enum as an integer or a struct in Rust and then pass it to Deno. On the Deno side, you can then interpret the received integer or struct as your enum. However, this approach requires you to manually manage the mapping between your enum and the integer or struct, and it may not work for complex enums. Here's an example of how you might do this:
#[repr(C)]
pub enum MyEvent {
Event = 1,
SubEvent = 2,
Nothing = 3,
}

#[no_mangle]
pub extern "C" fn run_event_loop(func: Option<extern "C" fn(u32)>) {
let callback = func.unwrap();
callback(MyEvent::Event as u32);
callback(MyEvent::SubEvent as u32);
callback(MyEvent::Nothing as u32);
}
#[repr(C)]
pub enum MyEvent {
Event = 1,
SubEvent = 2,
Nothing = 3,
}

#[no_mangle]
pub extern "C" fn run_event_loop(func: Option<extern "C" fn(u32)>) {
let callback = func.unwrap();
callback(MyEvent::Event as u32);
callback(MyEvent::SubEvent as u32);
callback(MyEvent::Nothing as u32);
}
And on the Deno side:
const onEvent = new Deno.UnsafeCallback(
{
parameters: ["u32"],
result: "void",
},
(eventType) => {
console.log(eventType);
}
);

const lib = Deno.dlopen("./target/debug/mylib.dylib", {
run_event_loop: { parameters: ["function"], result: "void" },
});

lib.symbols.run_event_loop(onEvent.pointer);
lib.close();
const onEvent = new Deno.UnsafeCallback(
{
parameters: ["u32"],
result: "void",
},
(eventType) => {
console.log(eventType);
}
);

const lib = Deno.dlopen("./target/debug/mylib.dylib", {
run_event_loop: { parameters: ["function"], result: "void" },
});

lib.symbols.run_event_loop(onEvent.pointer);
lib.close();
In this example, the Rust enum MyEvent is represented as an integer (u32), and this integer is passed to Deno through the FFI API. On the Deno side, the received integer
Deno AI Helper
Deno AI Helper5mo ago
is then interpreted as the enum MyEvent. Please note that this is a workaround and may not work for complex enums or enums with
furiouzz
furiouzz5mo ago
Is it a possible to pass the event type with the event?
NeTT
NeTT5mo ago
The easiest way would be passing around numbers but since you have different levels of info going around, maybe use serde?
furiouzz
furiouzz5mo ago
At the end, I want to use Event from winit. winit uses enums and subenums.