use std::mem::MaybeUninit;
use std::ptr;
use allocative::Key;
use allocative::Visitor;
use pagable::PagableDeserialize;
use pagable::PagableSerialize;
use starlark_syntax::slice_vec_ext::SliceExt;
use crate::collections::maybe_uninit_backport::maybe_uninit_write_slice;
use crate::pagable::vtable_register::register_special_avalue_frozen;
use crate::values::FreezeResult;
use crate::values::Freezer;
use crate::values::FrozenHeap;
use crate::values::FrozenValue;
use crate::values::Heap;
use crate::values::Tracer;
use crate::values::Value;
use crate::values::layout::avalue::AValue;
use crate::values::layout::avalue::AValueImpl;
use crate::values::layout::heap::maybe_uninit_slice_util::maybe_uninit_write_from_exact_size_iter;
use crate::values::layout::heap::repr::AValueForward;
use crate::values::layout::heap::repr::AValueHeader;
use crate::values::layout::heap::repr::AValueRepr;
use crate::values::layout::heap::repr::ForwardPtr;
use crate::values::types::tuple::value::FrozenTuple;
use crate::values::types::tuple::value::Tuple;
fn tuple_avalue<'v>(len: usize) -> AValueImpl<'v, AValueTuple> {
AValueImpl::<AValueTuple>::new(unsafe { Tuple::new(len) })
}
fn frozen_tuple_avalue<'fv>(len: usize) -> AValueImpl<'fv, AValueFrozenTuple> {
AValueImpl::<AValueFrozenTuple>::new(unsafe { FrozenTuple::new(len) })
}
struct AValueTuple;
impl<'v> AValue<'v> for AValueTuple {
type StarlarkValue = Tuple<'v>;
type ExtraElem = Value<'v>;
fn extra_len(value: &Tuple<'v>) -> usize {
value.len()
}
fn offset_of_extra() -> usize {
Tuple::offset_of_content()
}
fn visit_extra_allocative<'a, 'b: 'a>(
value: &Self::StarlarkValue,
visitor: &'a mut Visitor<'b>,
) {
visitor.visit_simple(
Key::new("content"),
std::mem::size_of::<Value>() * value.len(),
);
}
unsafe fn heap_freeze(
me: *mut AValueRepr<Self::StarlarkValue>,
freezer: &Freezer,
) -> FreezeResult<FrozenValue> {
unsafe {
debug_assert!(
(*me).payload.len() != 0,
"empty tuple is allocated statically"
);
AValueForward::assert_does_not_overwrite_extra::<Self>();
let content = (*me).payload.content();
let (fv, r, extra) = freezer
.frozen_heap()
.reserve_with_extra::<AValueFrozenTuple>(content.len());
AValueHeader::overwrite_with_forward::<Self::StarlarkValue>(
me,
ForwardPtr::new_frozen(fv),
);
let frozen_values = content.try_map(|v| freezer.freeze(*v))?;
r.fill(FrozenTuple::new(content.len()));
let extra = &mut *extra;
maybe_uninit_write_slice(extra, &frozen_values);
Ok(fv)
}
}
unsafe fn heap_copy(
me: *mut AValueRepr<Self::StarlarkValue>,
tracer: &Tracer<'v>,
) -> Value<'v> {
unsafe {
debug_assert!(
(*me).payload.len() != 0,
"empty tuple is allocated statically"
);
AValueForward::assert_does_not_overwrite_extra::<Self>();
let content = (*me).payload.content_mut();
let (v, r, extra) = tracer.reserve_with_extra::<Self>(content.len());
let x = AValueHeader::overwrite_with_forward::<Self::StarlarkValue>(
me,
ForwardPtr::new_unfrozen(v),
);
debug_assert_eq!(content.len(), x.len());
for elem in content.iter_mut() {
tracer.trace(elem);
}
r.fill(x);
let extra = &mut *extra;
maybe_uninit_write_slice(extra, content);
v
}
}
}
struct AValueFrozenTuple;
impl<'v> AValue<'v> for AValueFrozenTuple {
type StarlarkValue = FrozenTuple;
type ExtraElem = FrozenValue;
fn extra_len(value: &FrozenTuple) -> usize {
value.len()
}
fn offset_of_extra() -> usize {
FrozenTuple::offset_of_content()
}
fn visit_extra_allocative<'a, 'b: 'a>(
value: &Self::StarlarkValue,
visitor: &'a mut Visitor<'b>,
) {
visitor.visit_simple(
Key::new("content"),
std::mem::size_of::<FrozenValue>() * value.len(),
);
}
unsafe fn heap_freeze(
_me: *mut AValueRepr<Self::StarlarkValue>,
_freezer: &Freezer,
) -> FreezeResult<FrozenValue> {
panic!("already frozen");
}
unsafe fn heap_copy(
_me: *mut AValueRepr<Self::StarlarkValue>,
_tracer: &Tracer<'v>,
) -> Value<'v> {
panic!("shouldn't be copying frozen values");
}
fn starlark_serialize(
me: *const AValueRepr<Self::StarlarkValue>,
ctx: &mut dyn crate::pagable::StarlarkSerializeContext,
) -> crate::Result<()> {
let value = unsafe { &(*me).payload };
let content = value.content();
content.len().pagable_serialize(ctx.pagable())?;
for elem in content {
ctx.serialize_frozen_value(*elem)?;
}
Ok(())
}
fn starlark_deserialize(
me: *mut AValueRepr<Self::StarlarkValue>,
ctx: &mut dyn crate::pagable::StarlarkDeserializeContext<'_>,
) -> crate::Result<()> {
let len = usize::pagable_deserialize(ctx.pagable())?;
unsafe {
ptr::write(&mut (*me).payload, FrozenTuple::new(len));
let extra_offset = AValueRepr::<Self::StarlarkValue>::offset_of_payload()
+ <Self as AValue>::offset_of_extra();
let extra_ptr = (me as *mut u8).add(extra_offset) as *mut MaybeUninit<FrozenValue>;
for i in 0..len {
let fv = ctx.deserialize_frozen_value()?;
(*extra_ptr.add(i)).write(fv);
}
}
Ok(())
}
}
impl FrozenHeap {
pub(crate) fn alloc_tuple(&self, elems: &[FrozenValue]) -> FrozenValue {
if elems.is_empty() {
return FrozenValue::new_empty_tuple();
}
unsafe {
let (v, extra) = self.alloc_raw_extra::<_>(frozen_tuple_avalue(elems.len()));
let extra = &mut *extra;
maybe_uninit_write_slice(extra, elems);
v.to_frozen_value()
}
}
pub(crate) fn alloc_tuple_iter(
&self,
elems: impl IntoIterator<Item = FrozenValue>,
) -> FrozenValue {
let elems = elems.into_iter();
let (lower, upper) = elems.size_hint();
if Some(lower) == upper {
if lower == 0 {
return FrozenValue::new_empty_tuple();
}
unsafe {
let (v, extra) = self.alloc_raw_extra(frozen_tuple_avalue(lower));
let extra = &mut *extra;
maybe_uninit_write_from_exact_size_iter(extra, elems, FrozenValue::new_none());
v.to_frozen_value()
}
} else {
self.alloc_tuple(&elems.collect::<Vec<_>>())
}
}
}
impl<'v> Heap<'v> {
pub(crate) fn alloc_tuple(self, elems: &[Value<'v>]) -> Value<'v> {
if elems.is_empty() {
return Value::new_empty_tuple();
}
unsafe {
let (v, extra) = self.alloc_raw_extra(tuple_avalue(elems.len()));
let extra = &mut *extra;
maybe_uninit_write_slice(extra, elems);
v.to_value()
}
}
pub(crate) fn alloc_tuple_iter(self, elems: impl IntoIterator<Item = Value<'v>>) -> Value<'v> {
let elems = elems.into_iter();
let (lower, upper) = elems.size_hint();
if Some(lower) == upper {
if lower == 0 {
return Value::new_empty_tuple();
}
unsafe {
let (v, extra) = self.alloc_raw_extra(tuple_avalue(lower));
let extra = &mut *extra;
maybe_uninit_write_from_exact_size_iter(extra, elems, Value::new_none());
v.to_value()
}
} else {
self.alloc_tuple(&elems.collect::<Vec<_>>())
}
}
}
register_special_avalue_frozen!(FrozenTuple, AValueFrozenTuple);