use std::{
borrow::{Borrow, BorrowMut},
marker::PhantomData,
os::fd::AsFd as _,
};
use crate::{
Pod,
maps::{MapData, MapError, check_kv_size},
sys::{SyscallError, bpf_map_lookup_and_delete_elem, bpf_map_push_elem},
};
#[doc(alias = "BPF_MAP_TYPE_QUEUE")]
pub struct Queue<T, V: Pod> {
pub(crate) inner: T,
_v: PhantomData<V>,
}
impl<T: Borrow<MapData>, V: Pod> Queue<T, V> {
pub(crate) fn new(map: T) -> Result<Self, MapError> {
let data = map.borrow();
check_kv_size::<(), V>(data)?;
Ok(Self {
inner: map,
_v: PhantomData,
})
}
pub fn capacity(&self) -> u32 {
self.inner.borrow().obj.max_entries()
}
}
impl<T: BorrowMut<MapData>, V: Pod> Queue<T, V> {
pub fn pop(&mut self, flags: u64) -> Result<V, MapError> {
let fd = self.inner.borrow().fd().as_fd();
let value =
bpf_map_lookup_and_delete_elem::<u32, _>(fd, None, flags).map_err(|io_error| {
SyscallError {
call: "bpf_map_lookup_and_delete_elem",
io_error,
}
})?;
value.ok_or(MapError::ElementNotFound)
}
pub fn push(&mut self, value: impl Borrow<V>, flags: u64) -> Result<(), MapError> {
let fd = self.inner.borrow().fd().as_fd();
bpf_map_push_elem(fd, value.borrow(), flags)
.map_err(|io_error| SyscallError {
call: "bpf_map_push_elem",
io_error,
})
.map_err(Into::into)
}
}