use core::{iter, marker, mem, ops, ptr};
mod impls;
pub struct FifoA<T: ?Sized, D: ::DataBuf> {
_pd: marker::PhantomData<*const T>,
read_pos: usize,
write_pos: usize,
data: D,
}
impl<T: ?Sized, D: ::DataBuf> FifoA<T, D> {
pub fn new() -> Self
where
D: Default,
{
Self::with_buffer(D::default())
}
pub fn with_buffer(data: D) -> Self {
FifoA {
_pd: marker::PhantomData,
read_pos: 0,
write_pos: 0,
data,
}
}
fn meta_words() -> usize {
D::round_to_words(mem::size_of::<&T>() - mem::size_of::<usize>())
}
fn space_words(&self) -> usize {
self.data.as_ref().len() - self.write_pos
}
#[cfg(feature = "unsize")]
pub fn push_back<U: marker::Unsize<T>>(&mut self, v: U) -> Result<(), U>
where
(U, D::Inner): crate::AlignmentValid,
{
self.push_back_stable(v, |p| p)
}
pub fn push_back_stable<U, F: FnOnce(&U) -> &T>(&mut self, v: U, f: F) -> Result<(), U>
where
(U, D::Inner): crate::AlignmentValid,
{
<(U, Self) as crate::AlignmentValid>::check();
unsafe {
match self.push_inner(crate::check_fat_pointer(&v, f)) {
Ok((_, data)) => {
ptr::write(data.as_mut_ptr() as *mut U, v);
Ok(())
}
Err(_) => Err(v),
}
}
}
unsafe fn push_inner(&mut self, fat_ptr: &T) -> Result<(&mut [D::Inner], &mut [D::Inner]), ()> {
let bytes = mem::size_of_val(fat_ptr);
let words = D::round_to_words(bytes) + Self::meta_words();
if self.space_words() < words {
if self.space_words() + self.read_pos >= words {
self.compact();
}
if self.space_words() < words {
if let Err(_) = self.data.extend(self.write_pos + words) {
return Err(());
}
}
}
assert!(self.space_words() >= words);
let slot = &mut self.data.as_mut()[self.write_pos..][..words];
self.write_pos += words;
let (meta, rv) = slot.split_at_mut(Self::meta_words());
let mut ptr_raw: *const T = fat_ptr;
super::store_metadata(meta, &crate::ptr_as_slice(&mut ptr_raw)[1..]);
Ok((meta, rv))
}
pub fn compact(&mut self) {
if self.read_pos != 0 {
self.data.as_mut().rotate_left(self.read_pos);
self.write_pos -= self.read_pos;
self.read_pos = 0;
}
}
pub fn empty(&self) -> bool {
self.read_pos == self.write_pos
}
pub fn pop_front(&mut self) -> Option<PopHandle<T, D>> {
if self.read_pos == self.write_pos {
None
} else {
Some(PopHandle { parent: self })
}
}
pub fn front_mut(&mut self) -> Option<&mut T> {
if self.read_pos == self.write_pos {
None
} else {
Some(unsafe { &mut *self.front_raw() })
}
}
pub fn front(&self) -> Option<&T> {
if self.read_pos == self.write_pos {
None
} else {
Some(unsafe { &*self.front_raw() })
}
}
pub fn iter(&self) -> Iter<T, D> {
Iter(self, self.read_pos)
}
pub fn iter_mut(&mut self) -> IterMut<T, D> {
IterMut(self, self.read_pos)
}
fn front_raw(&self) -> *mut T {
assert!(self.read_pos < self.write_pos);
unsafe { self.raw_at(self.read_pos) }
}
unsafe fn raw_at(&self, pos: usize) -> *mut T {
assert!(pos >= self.read_pos);
assert!(pos < self.write_pos);
let meta = &self.data.as_ref()[pos..];
let mw = Self::meta_words();
super::make_fat_ptr(meta[mw..].as_ptr() as usize, &meta[..mw])
}
fn pop_front_inner(&mut self) {
unsafe {
let ptr = &mut *self.front_raw();
let len = mem::size_of_val(ptr);
ptr::drop_in_place(ptr);
let words = D::round_to_words(len);
self.read_pos += Self::meta_words() + words;
}
}
}
impl<D: ::DataBuf> FifoA<str, D> {
pub fn push_back_str(&mut self, v: &str) -> Result<(), ()> {
unsafe {
self.push_inner(v)
.map(|(_, d)| ptr::copy(v.as_bytes().as_ptr(), d.as_mut_ptr() as *mut u8, v.len()))
}
}
}
impl<D: ::DataBuf, T: Clone> FifoA<[T], D> {
pub fn push_cloned(&mut self, v: &[T]) -> Result<(), ()> {
unsafe {
let (meta, d) = self.push_inner(v)?;
crate::list_push_cloned(meta, d, v);
}
Ok(())
}
pub fn push_copied(&mut self, v: &[T]) -> Result<(), ()>
where
T: Copy,
{
unsafe {
self.push_inner(v).map(|(_, d)| {
ptr::copy(
v.as_ptr() as *const u8,
d.as_mut_ptr() as *mut u8,
mem::size_of_val(v),
)
})
}
}
}
impl<T: ?Sized, D: crate::DataBuf> ops::Drop for FifoA<T, D> {
fn drop(&mut self) {
while let Some(_) = self.pop_front() {}
}
}
impl<T: ?Sized, D: ::DataBuf + Default> Default for FifoA<T, D> {
fn default() -> Self {
FifoA::new()
}
}
pub struct PopHandle<'a, T: 'a + ?Sized, D: 'a + crate::DataBuf> {
parent: &'a mut FifoA<T, D>,
}
impl<'a, T: ?Sized, D: crate::DataBuf> ops::Deref for PopHandle<'a, T, D> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.parent.front_raw() }
}
}
impl<'a, T: ?Sized, D: crate::DataBuf> ops::DerefMut for PopHandle<'a, T, D> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.parent.front_raw() }
}
}
impl<'a, T: ?Sized, D: crate::DataBuf> ops::Drop for PopHandle<'a, T, D> {
fn drop(&mut self) {
self.parent.pop_front_inner();
}
}
pub struct Iter<'a, T: 'a + ?Sized, D: 'a + crate::DataBuf>(&'a FifoA<T, D>, usize);
impl<'a, T: 'a + ?Sized, D: 'a + crate::DataBuf> iter::Iterator for Iter<'a, T, D> {
type Item = &'a T;
fn next(&mut self) -> Option<&'a T> {
if self.1 == self.0.write_pos {
None
} else {
let rv = unsafe { &*self.0.raw_at(self.1) };
self.1 += FifoA::<T, D>::meta_words() + D::round_to_words(mem::size_of_val(rv));
Some(rv)
}
}
}
pub struct IterMut<'a, T: 'a + ?Sized, D: 'a + crate::DataBuf>(&'a mut FifoA<T, D>, usize);
impl<'a, T: 'a + ?Sized, D: 'a + crate::DataBuf> iter::Iterator for IterMut<'a, T, D> {
type Item = &'a mut T;
fn next(&mut self) -> Option<&'a mut T> {
if self.1 == self.0.write_pos {
None
} else {
let rv = unsafe { &mut *self.0.raw_at(self.1) };
self.1 += FifoA::<T, D>::meta_words() + D::round_to_words(mem::size_of_val(rv));
Some(rv)
}
}
}