use std::fmt;
use std::fmt::Display;
use std::ops::Deref;
use std::sync::Arc;
use std::sync::Mutex;
use allocative::Allocative;
use dupe::Clone_;
use dupe::Dupe;
use dupe::Dupe_;
use pagable::PagableDeserialize;
use pagable::PagableDeserializer;
use pagable::PagableSerialize;
use pagable::PagableSerializer;
use crate::cast::transmute;
use crate::pagable::starlark_deserialize::StarlarkDeserializeContext;
use crate::pagable::starlark_deserialize_context::HeapDeserializationState;
use crate::pagable::starlark_deserialize_context::StarlarkDeserializerImpl;
use crate::pagable::starlark_serialize::StarlarkSerializeContext;
use crate::pagable::starlark_serialize_context::StarlarkSerializerImpl;
use crate::typing::Ty;
use crate::values::AllocFrozenValue;
use crate::values::FrozenHeap;
use crate::values::FrozenHeapRef;
use crate::values::FrozenValue;
use crate::values::FrozenValueTyped;
use crate::values::OwnedRefFrozenRef;
use crate::values::StarlarkValue;
use crate::values::Value;
use crate::values::type_repr::StarlarkTypeRepr;
#[derive(Debug, thiserror::Error)]
enum OwnedError {
#[error("Expected value of type `{0}` but got `{1}`")]
WrongType(&'static str, String),
}
#[derive(Debug, Clone, Dupe, Allocative)]
pub struct OwnedFrozenValue {
owner: FrozenHeapRef,
value: FrozenValue,
}
impl Display for OwnedFrozenValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt(&self.value, f)
}
}
impl StarlarkTypeRepr for OwnedFrozenValue {
type Canonical = <FrozenValue as StarlarkTypeRepr>::Canonical;
fn starlark_type_repr() -> Ty {
FrozenValue::starlark_type_repr()
}
}
impl AllocFrozenValue for OwnedFrozenValue {
fn alloc_frozen_value(self, heap: &FrozenHeap) -> FrozenValue {
unsafe { self.owned_frozen_value(heap) }
}
}
impl OwnedFrozenValue {
pub unsafe fn new(owner: FrozenHeapRef, value: FrozenValue) -> Self {
Self { owner, value }
}
pub fn unpack_bool(&self) -> Option<bool> {
self.value.unpack_bool()
}
pub fn unpack_i32(&self) -> Option<i32> {
self.value.unpack_i32()
}
pub fn unpack_str(&self) -> Option<&str> {
self.value.unpack_str()
}
pub fn downcast<T: StarlarkValue<'static>>(self) -> Result<OwnedFrozenValueTyped<T>, Self> {
match FrozenValueTyped::new(self.value) {
Some(typed) => Ok(OwnedFrozenValueTyped {
owner: self.owner,
value: typed,
}),
None => Err(self),
}
}
pub fn downcast_starlark<T: StarlarkValue<'static>>(
self,
) -> crate::Result<OwnedFrozenValueTyped<T>> {
match self.downcast() {
Ok(v) => Ok(v),
Err(this) => Err(crate::Error::new_value(OwnedError::WrongType(
T::TYPE,
this.value.to_value().to_string_for_type_error(),
))),
}
}
pub fn value<'v>(&'v self) -> Value<'v> {
Value::new_frozen(self.value)
}
pub fn owned_value<'v>(&self, heap: &'v FrozenHeap) -> Value<'v> {
unsafe { self.owned_frozen_value(heap).to_value() }
}
pub fn map(&self, f: impl FnOnce(FrozenValue) -> FrozenValue) -> Self {
Self {
owner: self.owner.dupe(),
value: f(self.value),
}
}
pub fn try_map<E>(
&self,
f: impl FnOnce(FrozenValue) -> Result<FrozenValue, E>,
) -> Result<Self, E> {
Ok(Self {
owner: self.owner.dupe(),
value: f(self.value)?,
})
}
pub fn owner(&self) -> &FrozenHeapRef {
&self.owner
}
pub unsafe fn unchecked_frozen_value(&self) -> FrozenValue {
self.value
}
pub unsafe fn owned_frozen_value(&self, heap: &FrozenHeap) -> FrozenValue {
heap.add_reference(&self.owner);
self.value
}
}
impl PagableSerialize for OwnedFrozenValue {
fn pagable_serialize(&self, serializer: &mut dyn PagableSerializer) -> pagable::Result<()> {
self.owner.pagable_serialize(serializer)?;
let state = StarlarkSerializerImpl::get_or_create_state(serializer);
state.ensure_offset_maps_registered(&self.owner);
let mut ctx = StarlarkSerializerImpl::new(serializer, state);
ctx.serialize_frozen_value(self.value)
.map_err(|e| e.into_anyhow())?;
Ok(())
}
}
impl<'de> PagableDeserialize<'de> for OwnedFrozenValue {
fn pagable_deserialize<D: PagableDeserializer<'de> + ?Sized>(
deserializer: &mut D,
) -> pagable::Result<Self> {
let owner = FrozenHeapRef::pagable_deserialize(deserializer)?;
let state = StarlarkDeserializerImpl::get_or_create_state(deserializer.as_dyn());
let mut ctx = StarlarkDeserializerImpl::new(
deserializer.as_dyn(),
state,
Arc::new(Mutex::new(HeapDeserializationState::empty())),
);
let value = ctx
.deserialize_frozen_value()
.map_err(|e| e.into_anyhow())?;
Ok(unsafe { OwnedFrozenValue::new(owner, value) })
}
}
#[derive(Debug, Clone_, Dupe_, Allocative)]
pub struct OwnedFrozenValueTyped<T: StarlarkValue<'static>> {
owner: FrozenHeapRef,
value: FrozenValueTyped<'static, T>,
}
impl<T: StarlarkValue<'static>> Deref for OwnedFrozenValueTyped<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.value.as_ref()
}
}
impl<T: for<'a> StarlarkValue<'a>> OwnedFrozenValueTyped<T> {
pub unsafe fn new<'a>(owner: FrozenHeapRef, value: FrozenValueTyped<'a, T>) -> Self {
let value = unsafe {
std::mem::transmute::<FrozenValueTyped<'a, T>, FrozenValueTyped<'static, T>>(value)
};
Self { owner, value }
}
pub unsafe fn to_frozen_value(&self) -> FrozenValue {
self.value.to_frozen_value()
}
pub fn to_value<'v>(&'v self) -> Value<'v> {
unsafe { self.to_frozen_value().to_value() }
}
pub fn to_owned_frozen_value(&self) -> OwnedFrozenValue {
OwnedFrozenValue {
owner: self.owner.dupe(),
value: self.value.to_frozen_value(),
}
}
pub fn as_owned_ref_frozen_ref(&self) -> OwnedRefFrozenRef<'_, T> {
unsafe { OwnedRefFrozenRef::new_unchecked(self.value.as_ref(), &self.owner) }
}
pub fn owner(&self) -> &FrozenHeapRef {
&self.owner
}
pub fn as_ref(&self) -> &T {
self.value.as_ref()
}
pub unsafe fn value_typed(&self) -> FrozenValueTyped<'static, T> {
self.value
}
pub fn owned_frozen_value_typed(&self, heap: &FrozenHeap) -> FrozenValueTyped<'static, T> {
heap.add_reference(&self.owner);
self.value
}
pub fn owned_frozen_value(&self, heap: &FrozenHeap) -> FrozenValue {
self.owned_frozen_value_typed(heap).to_frozen_value()
}
pub fn owned_value<'v>(&self, heap: &'v FrozenHeap) -> Value<'v> {
self.owned_frozen_value(heap).to_value()
}
pub fn owned_as_ref<'v>(&self, heap: &'v FrozenHeap) -> &'v T {
self.owned_value(heap);
unsafe { transmute!(&T, &T, self.as_ref()) }
}
pub fn map<U: for<'a> StarlarkValue<'a>>(
&self,
f: impl for<'a> FnOnce(FrozenValueTyped<'a, T>) -> FrozenValueTyped<'a, U>,
) -> OwnedFrozenValueTyped<U> {
OwnedFrozenValueTyped {
owner: self.owner.dupe(),
value: f(self.value),
}
}
pub fn try_map<U: for<'a> StarlarkValue<'a>, E>(
&self,
f: impl for<'a> FnOnce(FrozenValueTyped<'a, T>) -> Result<FrozenValueTyped<'a, U>, E>,
) -> Result<OwnedFrozenValueTyped<U>, E> {
Ok(OwnedFrozenValueTyped {
owner: self.owner.dupe(),
value: f(self.value)?,
})
}
pub fn maybe_map<U: for<'a> StarlarkValue<'a>>(
&self,
f: impl for<'a> FnOnce(FrozenValueTyped<'a, T>) -> Option<FrozenValueTyped<'a, U>>,
) -> Option<OwnedFrozenValueTyped<U>> {
Some(OwnedFrozenValueTyped {
owner: self.owner.dupe(),
value: f(self.value)?,
})
}
}
impl<T: for<'a> StarlarkValue<'a>> PagableSerialize for OwnedFrozenValueTyped<T> {
fn pagable_serialize(&self, serializer: &mut dyn PagableSerializer) -> pagable::Result<()> {
self.to_owned_frozen_value().pagable_serialize(serializer)
}
}
impl<'de, T: for<'a> StarlarkValue<'a>> PagableDeserialize<'de> for OwnedFrozenValueTyped<T> {
fn pagable_deserialize<D: PagableDeserializer<'de> + ?Sized>(
deserializer: &mut D,
) -> pagable::Result<Self> {
let owned = OwnedFrozenValue::pagable_deserialize(deserializer)?;
match owned.downcast::<T>() {
Ok(typed) => Ok(typed),
Err(owned) => Err(anyhow::anyhow!(
"OwnedFrozenValueTyped deserialization: expected type `{}`, got `{}`",
T::TYPE,
owned.value().to_string_for_type_error()
)),
}
}
}