use alloc::boxed::Box;
use wasefire_applet_api::button as api;
use wasefire_common::ptr::SharedPtr;
use wasefire_error::Error;
pub use self::api::State;
pub use self::api::State::*;
use crate::{convert, convert_unit};
pub fn count() -> usize {
convert(unsafe { api::count() }).unwrap_or(0)
}
pub trait Handler: 'static {
fn event(&self, state: State);
}
impl<F: Fn(State) + 'static> Handler for F {
fn event(&self, state: State) {
self(state)
}
}
#[must_use]
pub struct Listener<H: Handler> {
button: usize,
handler: SharedPtr<H>,
}
impl<H: Handler> Listener<H> {
pub fn new(button: usize, handler: H) -> Result<Self, Error> {
let handler_func = Self::call;
let handler = Box::into_raw(Box::new(handler));
let handler_data = handler as *const u8;
let params = api::register::Params { button, handler_func, handler_data };
convert_unit(unsafe { api::register(params) })?;
Ok(Listener { button, handler: SharedPtr(handler) })
}
pub fn stop(self) {
core::mem::drop(self);
}
pub fn leak(self) {
core::mem::forget(self);
}
extern "C" fn call(data: *const u8, state: usize) {
let handler = unsafe { &*(data as *const H) };
let state = state.into();
handler.event(state);
}
}
impl<H: Handler> Drop for Listener<H> {
fn drop(&mut self) {
let params = api::unregister::Params { button: self.button };
convert_unit(unsafe { api::unregister(params) }).unwrap();
drop(unsafe { Box::from_raw(self.handler.0 as *mut H) });
}
}