use std::cell::{Cell, RefCell};
use super::{ID_CAPACITY, Report, Source, VALUES};
pub const PAD_CONNECTED: u32 = 1 << 0;
pub const PAD_STANDARD: u32 = 1 << 1;
#[derive(Debug)]
struct Frame {
reported: bool,
pads: Vec<Report>,
}
thread_local! {
static VALUE_SCRATCH: Cell<[f32; VALUES]> = const { Cell::new([0.0; VALUES]) };
static ID_SCRATCH: Cell<[u8; ID_CAPACITY]> = const { Cell::new([0; ID_CAPACITY]) };
static FRAME: RefCell<Frame> = const {
RefCell::new(Frame {
reported: false,
pads: Vec::new(),
})
};
}
#[cfg_attr(target_arch = "wasm32", unsafe(no_mangle))]
pub extern "C" fn __crcbl_web_pad_values_ptr() -> *mut f32 {
VALUE_SCRATCH.with(|slot| slot.as_ptr().cast::<f32>())
}
#[cfg_attr(target_arch = "wasm32", unsafe(no_mangle))]
pub extern "C" fn __crcbl_web_pad_values_capacity() -> u32 {
u32::try_from(VALUES).unwrap_or(u32::MAX)
}
#[cfg_attr(target_arch = "wasm32", unsafe(no_mangle))]
pub extern "C" fn __crcbl_web_pad_id_ptr() -> *mut u8 {
ID_SCRATCH.with(|slot| slot.as_ptr().cast::<u8>())
}
#[cfg_attr(target_arch = "wasm32", unsafe(no_mangle))]
pub extern "C" fn __crcbl_web_pad_id_capacity() -> u32 {
u32::try_from(ID_CAPACITY).unwrap_or(u32::MAX)
}
#[cfg_attr(target_arch = "wasm32", unsafe(no_mangle))]
pub extern "C" fn __crcbl_web_pad_begin() {
FRAME.with_borrow_mut(|frame| {
frame.reported = true;
frame.pads.clear();
});
}
#[cfg_attr(target_arch = "wasm32", unsafe(no_mangle))]
pub extern "C" fn __crcbl_web_pad(index: u32, flags: u32, pressed: u32, id_len: u32) {
let values = VALUE_SCRATCH.with(Cell::get);
let id = ID_SCRATCH.with(Cell::get);
let id_len = usize::try_from(id_len).map_or(ID_CAPACITY, |len| len.min(ID_CAPACITY));
FRAME.with_borrow_mut(|frame| {
frame.pads.push(Report {
index,
connected: flags & PAD_CONNECTED != 0,
standard: flags & PAD_STANDARD != 0,
pressed,
values,
id,
id_len,
});
});
}
#[derive(Debug)]
pub(super) struct Bridge;
impl Source for Bridge {
fn take(&mut self, into: &mut Vec<Report>) -> bool {
FRAME.with_borrow_mut(|frame| {
if !frame.reported {
return false;
}
frame.reported = false;
into.clear();
std::mem::swap(into, &mut frame.pads);
true
})
}
}