use std::{cell, marker, mem};
use arena::{Returned, Slot};
use provided::view;
use crate::{
buffer,
buffer::storage::{provided, provided::arena},
mem::lease,
};
pub struct Vacant<'d, T, L = cell::Cell<u32>, C: Copy = ()> {
pub(super) node: crate::mem::Lease<arena::Empty<'d>, lease::Open>,
pub(super) domain: marker::PhantomData<&'d Slot<'d, T, L>>,
pub(super) context: C,
}
impl<'d, T, L, C: Copy> Vacant<'d, T, L, C> {
pub(in crate::buffer::storage::provided) fn entry(&self) -> &'d Slot<'d, T, L> {
unsafe { &*self.node.sink().entry.cast::<Slot<'d, T, L>>().as_ptr() }
}
pub(in crate::buffer) fn insert_with(
self,
item: T,
project: impl for<'id> FnOnce(
&'d mut T,
buffer::raw::Limit<'id>,
) -> buffer::raw::Projection<'d, 'id>,
) -> provided::Unique<'d> {
let pending = self.initialize(item);
let resident = unsafe { arena::Entry::resident(pending.node.entry) };
let slot = pending.entry();
let item = unsafe { (*slot.item.get()).assume_init_mut() };
buffer::raw::Limit::scope(resident, |limit| pending.publish(project(item, limit)))
}
fn initialize(self, item: T) -> Returned<'d, T, L> {
unsafe { (*self.entry().item.get()).write(item) };
let (node, ()) = self.node.into_parts();
Returned {
node: arena::Entry::initialize(node),
domain: marker::PhantomData,
}
}
}
const _: () = {
assert!(mem::offset_of!(Slot<'_, u8, ()>, item) == usize::BITS as usize);
assert!(mem::offset_of!(Slot<'_, u64, cell::Cell<u32>>, item) == usize::BITS as usize);
};
impl<'d, T> Vacant<'d, T> {
pub fn try_insert(
self,
item: T,
resident: u32,
project: impl for<'a> FnOnce(&'a mut T) -> &'a mut [u8],
) -> Result<provided::Unique<'d>, crate::mem::Rejected<T, view::LengthError>> {
self.entry().set_resident(resident);
let pending = self.initialize(item);
buffer::raw::Limit::scope(resident, |limit| {
let slot = pending.entry();
let item = unsafe { (*slot.item.get()).assume_init_mut() };
let view = match limit.try_project(project(item)) {
Ok(view) => view,
Err(error) => return Err(pending.reject(error)),
};
Ok(pending.publish(view))
})
}
pub fn try_adopt<P: buffer::raw::Input<T>>(
self,
item: P,
resident: u32,
) -> Result<provided::Unique<'d>, crate::mem::Rejected<P, view::LengthError>> {
self.entry().set_resident(resident);
let len = item.bytes().len();
if len > resident as usize {
return Err(crate::mem::Rejected::new(
item,
view::LengthError::new(len, resident),
));
}
let (item, project) = item.into_item();
Ok(self.insert_with(item, |item, limit| {
unsafe { limit.project(project(item)) }
}))
}
}
impl<'d, T, C> Vacant<'d, T, (), &'d C> {
pub fn context(&self) -> &'d C {
self.context
}
}
const _: () = {
assert!(size_of::<Vacant<'static, ()>>() == size_of::<usize>());
assert!(size_of::<Vacant<'static, (), (), &'static ()>>() == 2 * size_of::<usize>());
};