use super::{DstArray, DstBuf, check_fat_pointer, decompose_pointer, store_metadata};
#[cfg(doc)]
use crate::MaybeUninit;
use crate::{ManuallyDrop, Mem, MemAligned};
use ::core::{marker, ptr};
#[doc = crate::_tags!(data_structure)]
#[doc = crate::_doc_location!("data/layout/dst")]
pub type DstValueUsize<DST , const CAP: usize> = DstValue<DST, DstArray<usize, CAP>>;
#[doc = crate::_tags!(data_structure)]
#[doc = crate::_doc_location!("data/layout/dst")]
pub struct DstValue<DST: ?Sized, BUF: DstBuf> {
_pd: marker::PhantomData<DST>,
data: BUF,
}
impl<DST: ?Sized, BUF: DstBuf> DstValue<DST, BUF> {
pub fn new<VAL, F>(val: VAL, get_ref: F) -> Result<DstValue<DST, BUF>, VAL>
where
F: FnOnce(&VAL) -> &DST,
(VAL, BUF::Inner): MemAligned,
BUF: Default,
{
Self::in_buffer(BUF::default(), val, get_ref)
}
pub fn in_buffer<VAL, F: FnOnce(&VAL) -> &DST>(
buffer: BUF,
val: VAL,
get_ref: F,
) -> Result<DstValue<DST, BUF>, VAL>
where
(VAL, BUF::Inner): MemAligned,
{
<(VAL, BUF::Inner) as MemAligned>::assert_compatibility();
let rv = unsafe {
let ptr: *const _ = check_fat_pointer(&val, get_ref);
let (raw_ptr, meta_len, meta) = decompose_pointer(ptr);
DstValue::new_raw(&meta[..meta_len], raw_ptr.cast_mut(), size_of::<VAL>(), buffer)
};
match rv {
Some(r) => {
Mem::forget(val);
Ok(r)
}
None => Err(val),
}
}
pub unsafe fn new_raw(
info: &[usize],
data: *mut (),
size: usize,
mut buffer: BUF,
) -> Option<DstValue<DST, BUF>> {
let req_words = BUF::round_to_words(size_of_val(info)) + BUF::round_to_words(size);
if buffer.extend(req_words).is_err() {
return None;
}
let mut rv =
ManuallyDrop::new(DstValue::<DST, BUF> { _pd: marker::PhantomData, data: buffer });
unsafe {
rv.write_value(data, size, info);
}
Some(ManuallyDrop::into_inner(rv))
}
pub fn replace<VAL>(&mut self, val: VAL, get_ref: impl Fn(&VAL) -> &DST) -> Result<(), VAL>
where
(VAL, BUF::Inner): MemAligned,
{
<(VAL, BUF::Inner) as MemAligned>::assert_compatibility();
let size = size_of::<VAL>();
let (raw_ptr, meta_len, meta) = decompose_pointer(check_fat_pointer(&val, get_ref));
let info = &meta[..meta_len];
let req_words = BUF::round_to_words(size_of_val(info)) + BUF::round_to_words(size);
if self.data.extend(req_words).is_err() {
return Err(val);
}
unsafe {
ptr::drop_in_place::<DST>(&mut **self);
self.write_value(raw_ptr, size_of::<VAL>(), info);
}
Ok(())
}
}
impl<BUF: DstBuf> DstValue<str, BUF> {
pub fn empty_str() -> Result<Self, ()>
where
BUF: Default,
{
Self::empty_str_in_buffer(Default::default())
}
pub fn empty_str_in_buffer(buffer: BUF) -> Result<Self, ()> {
let rv = unsafe {
let (raw_ptr, meta_len, meta) = decompose_pointer("");
DstValue::new_raw(&meta[..meta_len], raw_ptr.cast_mut(), 0, buffer)
};
match rv {
Some(r) => Ok(r),
None => Err(()),
}
}
pub fn new_str(v: &str) -> Result<Self, &str>
where
BUF: Default,
{
Self::new_str_in_buffer(Default::default(), v)
}
pub fn new_str_in_buffer(buffer: BUF, val: &str) -> Result<Self, &str> {
let rv = unsafe {
let (raw_ptr, meta_len, meta) = decompose_pointer(val);
DstValue::new_raw(&meta[..meta_len], raw_ptr.cast_mut(), size_of_val(val), buffer)
};
match rv {
Some(r) => Ok(r),
None => Err(val),
}
}
pub fn append_str(&mut self, val: &str) -> Result<(), ()> {
let info_words = BUF::round_to_words(size_of::<usize>());
let ofs = self.len();
let req_words = BUF::round_to_words(ofs + val.len()) + info_words;
if self.data.extend(req_words).is_err() {
return Err(());
}
let data = self.data.as_mut();
let info_ofs = data.len() - info_words;
unsafe {
ptr::copy_nonoverlapping(
val.as_ptr(),
(data.as_mut_ptr() as *mut u8).add(ofs),
val.len(),
);
store_metadata(&mut data[info_ofs..], &[ofs + val.len()]);
}
Ok(())
}
pub fn truncate(&mut self, len: usize) {
if len < self.len() {
let _ = &self[..][len..];
let info_words = BUF::round_to_words(size_of::<usize>());
let data = self.data.as_mut();
let info_ofs = data.len() - info_words;
store_metadata(&mut data[info_ofs..], &[len]);
}
}
}
impl<I, BUF: DstBuf> DstValue<[I], BUF>
where
(I, BUF::Inner): MemAligned,
{
pub fn empty_slice() -> Result<Self, ()>
where
BUF: Default,
{
Self::empty_slice_with_buffer(Default::default())
}
pub fn empty_slice_with_buffer(mut buffer: BUF) -> Result<Self, ()> {
<(I, BUF::Inner) as MemAligned>::assert_compatibility();
let info_words = BUF::round_to_words(size_of::<usize>());
let req_words = info_words;
if buffer.extend(req_words).is_err() {
return Err(());
}
assert!(req_words <= buffer.as_ref().len());
let mut rv = DstValue { _pd: marker::PhantomData, data: buffer };
let data = rv.data.as_mut();
let info_ofs = data.len() - info_words;
let (_data_dst, info_dst) = data.split_at_mut(info_ofs);
store_metadata(info_dst, &[0]);
Ok(rv)
}
pub fn append(&mut self, v: I) -> Result<(), I> {
let info_words = BUF::round_to_words(size_of::<usize>());
let ofs = self.len();
let req_words = BUF::round_to_words((ofs + 1) * size_of::<I>()) + info_words;
if self.data.extend(req_words).is_err() {
return Err(v);
}
let data = self.data.as_mut();
assert!(req_words <= data.len());
unsafe {
let data_ptr = (data.as_ptr() as *mut I).add(ofs);
ptr::write(data_ptr, v);
}
let info_ofs = data.len() - info_words;
store_metadata(&mut data[info_ofs..], &[ofs + 1]);
Ok(())
}
pub fn appended(mut self, v: I) -> Result<Self, (Self, I)> {
match self.append(v) {
Ok(()) => Ok(self),
Err(v) => Err((self, v)),
}
}
pub fn extend<It: Iterator<Item = I>>(&mut self, mut iter: It) -> Result<(), (I, It)> {
while let Some(v) = iter.next() {
match self.append(v) {
Ok(()) => {}
Err(v) => return Err((v, iter)),
}
}
Ok(())
}
pub fn extended<It: Iterator<Item = I>>(mut self, iter: It) -> Result<Self, (Self, I, It)> {
match self.extend(iter) {
Ok(()) => Ok(self),
Err((v, iter)) => Err((self, v, iter)),
}
}
pub fn pop(&mut self) -> Option<I> {
if !self.is_empty() {
let ofs = self.len() - 1;
let data = self.data.as_mut();
let info_words = BUF::round_to_words(size_of::<usize>());
let info_ofs = data.len() - info_words;
unsafe {
store_metadata(&mut data[info_ofs..], &[ofs]);
Some(ptr::read((data.as_ptr() as *const I).add(ofs)))
}
} else {
None
}
}
}
impl<DST: ?Sized, BUF: DstBuf> DstValue<DST, BUF> {
unsafe fn write_value(&mut self, data: *const (), size: usize, info: &[usize]) {
let info_words = BUF::round_to_words(size_of_val(info));
let req_words = info_words + BUF::round_to_words(size);
let buf = self.data.as_mut();
assert!(req_words <= buf.len());
{
let info_ofs = buf.len() - info_words;
let info_dst = &mut buf[info_ofs..];
store_metadata(info_dst, info);
}
unsafe {
ptr::copy_nonoverlapping(data as *const u8, buf.as_mut_ptr() as *mut u8, size);
}
}
unsafe fn as_ptr(&self) -> *mut DST {
let data = self.data.as_ref();
let info_size = size_of::<*mut DST>() / size_of::<usize>() - 1;
let info_ofs = data.len() - BUF::round_to_words(info_size * size_of::<usize>());
let (data, meta) = data.split_at(info_ofs);
unsafe { super::make_fat_ptr(data.as_ptr() as *mut (), meta) }
}
unsafe fn as_ptr_mut(&mut self) -> *mut DST {
let data = self.data.as_mut();
let info_size = size_of::<*mut DST>() / size_of::<usize>() - 1;
let info_ofs = data.len() - BUF::round_to_words(info_size * size_of::<usize>());
let (data, meta) = data.split_at_mut(info_ofs);
unsafe { super::make_fat_ptr(data.as_mut_ptr() as *mut (), meta) }
}
}
mod core_impls {
use super::{DstBuf, DstValue};
use core::{fmt, future, iter, ops, pin, ptr, task};
impl<DST: ?Sized, BUF: DstBuf> ops::Deref for DstValue<DST, BUF> {
type Target = DST;
fn deref(&self) -> &DST {
unsafe { &*self.as_ptr() }
}
}
impl<DST: ?Sized, BUF: DstBuf> ops::DerefMut for DstValue<DST, BUF> {
fn deref_mut(&mut self) -> &mut DST {
unsafe { &mut *self.as_ptr_mut() }
}
}
impl<DST: ?Sized, BUF: DstBuf> ops::Drop for DstValue<DST, BUF> {
fn drop(&mut self) {
unsafe { ptr::drop_in_place(&mut **self) }
}
}
macro_rules! impl_trait {
( $t:path; $($body:tt)* ) => {
impl<BUF: DstBuf, DST: ?Sized> $t for DstValue<DST, BUF> where DST: $t { $( $body )* }
}
}
impl_trait! { future::Future;
type Output = DST::Output;
fn poll(self: pin::Pin<&mut Self>, cx: &mut task::Context) -> task::Poll<Self::Output> {
unsafe { pin::Pin::new_unchecked(&mut **self.get_unchecked_mut()).poll(cx) }
}
}
impl_trait! { iter::Iterator;
type Item = DST::Item;
fn next(&mut self) -> Option<Self::Item> {
(**self).next()
}
}
impl_trait! { iter::DoubleEndedIterator;
fn next_back(&mut self) -> Option<Self::Item> {
(**self).next_back()
}
}
impl_trait! { iter::ExactSizeIterator; }
macro_rules! impl_fmt {
( $( $t:ident )* ) => {
$(
impl_trait!{ fmt::$t;
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
(**self).fmt(f)
}
}
)*
}
}
impl_fmt! {
Display Debug UpperHex LowerHex
}
}