use std::any::TypeId;
use std::any::type_name;
use std::marker::PhantomData;
use std::mem;
use super::simple::AValueSimple;
use crate::eval::compiler::def::FrozenDef;
use crate::private::Private;
use crate::values::ComplexValue;
use crate::values::FreezeError;
use crate::values::FreezeResult;
use crate::values::Freezer;
use crate::values::FrozenValue;
use crate::values::FrozenValueTyped;
use crate::values::Heap;
use crate::values::HeapSendable;
use crate::values::StarlarkValue;
use crate::values::Trace;
use crate::values::Tracer;
use crate::values::Value;
use crate::values::layout::avalue::AValue;
use crate::values::layout::avalue::AValueImpl;
use crate::values::layout::avalue::AValueSimpleBound;
use crate::values::layout::avalue::heap_copy_impl;
use crate::values::layout::avalue::try_freeze_directly;
use crate::values::layout::heap::repr::AValueHeader;
use crate::values::layout::heap::repr::AValueRepr;
use crate::values::layout::heap::repr::ForwardPtr;
#[derive(Debug, thiserror::Error)]
enum AValueError {
#[error("Value of type `{0}` cannot be frozen")]
CannotBeFrozen(&'static str),
}
struct AValueComplex<T>(PhantomData<T>);
impl<'v, T> AValue<'v> for AValueComplex<T>
where
T: ComplexValue<'v>,
T::Frozen: AValueSimpleBound<'static>,
{
type StarlarkValue = T;
type ExtraElem = ();
fn extra_len(_value: &T) -> usize {
0
}
fn offset_of_extra() -> usize {
mem::size_of::<Self>()
}
unsafe fn heap_freeze(
me: *mut AValueRepr<Self::StarlarkValue>,
freezer: &Freezer,
) -> FreezeResult<FrozenValue> {
unsafe {
if let Some(f) = try_freeze_directly::<Self>(me, freezer) {
return f;
}
let (fv, r) = freezer.reserve::<AValueSimple<T::Frozen>>();
let x = AValueHeader::overwrite_with_forward::<Self::StarlarkValue>(
me,
ForwardPtr::new_frozen(fv),
);
let res = x.freeze(freezer)?;
r.fill(res);
if TypeId::of::<T::Frozen>() == TypeId::of::<FrozenDef>() {
let frozen_def = FrozenValueTyped::new(fv).unwrap();
freezer.frozen_defs.borrow_mut().push(frozen_def);
}
Ok(fv)
}
}
unsafe fn heap_copy(
me: *mut AValueRepr<Self::StarlarkValue>,
tracer: &Tracer<'v>,
) -> Value<'v> {
unsafe { heap_copy_impl::<Self>(me, tracer, Trace::trace) }
}
}
pub(crate) struct AValueComplexNoFreeze<T>(PhantomData<T>);
impl<'v, T> AValue<'v> for AValueComplexNoFreeze<T>
where
T: StarlarkValue<'v> + Trace<'v>,
{
type StarlarkValue = T;
type ExtraElem = ();
fn extra_len(_value: &T) -> usize {
0
}
fn offset_of_extra() -> usize {
mem::size_of::<Self::StarlarkValue>()
}
unsafe fn heap_freeze(
_me: *mut AValueRepr<Self::StarlarkValue>,
_freezer: &Freezer,
) -> FreezeResult<FrozenValue> {
Err(FreezeError::new(
AValueError::CannotBeFrozen(type_name::<T>()).to_string(),
))
}
unsafe fn heap_copy(
me: *mut AValueRepr<Self::StarlarkValue>,
tracer: &Tracer<'v>,
) -> Value<'v> {
unsafe { heap_copy_impl::<Self>(me, tracer, Trace::trace) }
}
}
impl<'v> Heap<'v> {
pub fn alloc_complex<T>(self, x: T) -> Value<'v>
where
T: ComplexValue<'v>,
T::Frozen: AValueSimpleBound<'static>,
T: HeapSendable<'v>,
{
assert!(!T::is_special(Private));
self.alloc_raw(AValueImpl::<AValueComplex<T>>::new(x))
.to_value()
}
pub fn alloc_complex_no_freeze<T>(self, x: T) -> Value<'v>
where
T: StarlarkValue<'v> + Trace<'v>,
T: HeapSendable<'v>,
{
assert!(!T::is_special(Private));
self.alloc_raw(AValueImpl::<AValueComplexNoFreeze<T>>::new(x))
.to_value()
}
}