use core::ffi::c_void;
use core::time::Duration;
use flipperzero_sys as sys;
use flipperzero_sys::furi::{Status, duration_to_ticks};
use crate::furi;
pub struct MessageQueue<M: Sized> {
hnd: *mut sys::FuriMessageQueue,
_marker: core::marker::PhantomData<M>,
}
impl<M: Sized> MessageQueue<M> {
pub fn new(capacity: usize) -> Self {
Self {
hnd: unsafe { sys::furi_message_queue_alloc(capacity as u32, core::mem::size_of::<M>() as u32) },
_marker: core::marker::PhantomData::<M>,
}
}
pub fn put(&self, msg: M, timeout: Duration) -> furi::Result<()> {
let mut msg = core::mem::ManuallyDrop::new(msg);
let timeout_ticks = sys::furi::duration_to_ticks(timeout);
let status: Status = unsafe {
sys::furi_message_queue_put(self.hnd, &mut msg as *mut _ as *const c_void, timeout_ticks).into()
};
status.err_or(())
}
pub fn get(&self, timeout: Duration) -> furi::Result<M> {
let timeout_ticks = duration_to_ticks(timeout);
let mut out = core::mem::MaybeUninit::<M>::uninit();
let status: Status =
unsafe { sys::furi_message_queue_get(self.hnd, out.as_mut_ptr() as *mut c_void, timeout_ticks).into() };
if status.is_ok() {
Ok(unsafe { out.assume_init() })
} else {
Err(status)
}
}
pub fn capacity(&self) -> usize {
unsafe { sys::furi_message_queue_get_capacity(self.hnd) as usize }
}
pub fn len(&self) -> usize {
unsafe { sys::furi_message_queue_get_count(self.hnd) as usize }
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn space(&self) -> usize {
unsafe { sys::furi_message_queue_get_space(self.hnd) as usize }
}
}
impl<M: Sized> Drop for MessageQueue<M> {
fn drop(&mut self) {
while !self.is_empty() {
match self.get(Duration::MAX) {
Ok(msg) => drop(msg),
Err(_) => break, }
}
unsafe { sys::furi_message_queue_free(self.hnd) }
}
}