use std::{fmt, fmt::Display, ops::Deref};
use gazebo::prelude::*;
use crate::values::{
none::NoneType, AllocFrozenValue, FrozenHeap, FrozenHeapRef, FrozenValue, FrozenValueTyped,
StarlarkValue, Value,
};
#[derive(Debug, Clone, Dupe)]
pub struct OwnedFrozenValue {
owner: FrozenHeapRef,
value: FrozenValue,
}
impl Default for OwnedFrozenValue {
fn default() -> Self {
OwnedFrozenValue::alloc(NoneType)
}
}
impl Display for OwnedFrozenValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt(&self.value, f)
}
}
impl OwnedFrozenValue {
pub unsafe fn new(owner: FrozenHeapRef, value: FrozenValue) -> Self {
Self { owner, value }
}
pub fn alloc(x: impl AllocFrozenValue) -> Self {
let heap = FrozenHeap::new();
let val = heap.alloc(x);
unsafe { Self::new(heap.into_ref(), val) }
}
pub fn unpack_bool(&self) -> Option<bool> {
self.value.unpack_bool()
}
pub fn unpack_int(&self) -> Option<i32> {
self.value.unpack_int()
}
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 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
}
}
#[derive(Debug, Clone_, Dupe_)]
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: StarlarkValue<'static>> OwnedFrozenValueTyped<T> {
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 owner(&self) -> &FrozenHeapRef {
&self.owner
}
pub fn as_ref(&self) -> &T {
self.value.as_ref()
}
pub unsafe fn owned_frozen_value(&self, heap: &FrozenHeap) -> FrozenValue {
heap.add_reference(&self.owner);
self.value.to_frozen_value()
}
pub fn owned_value<'v>(&self, heap: &'v FrozenHeap) -> Value<'v> {
unsafe { self.owned_frozen_value(heap).to_value() }
}
pub fn map<U: StarlarkValue<'static>>(
&self,
f: impl FnOnce(FrozenValueTyped<T>) -> FrozenValueTyped<U>,
) -> OwnedFrozenValueTyped<U> {
OwnedFrozenValueTyped {
owner: self.owner.dupe(),
value: f(self.value),
}
}
pub fn try_map<U: StarlarkValue<'static>, E>(
&self,
f: impl FnOnce(FrozenValueTyped<T>) -> Result<FrozenValueTyped<U>, E>,
) -> Result<OwnedFrozenValueTyped<U>, E> {
Ok(OwnedFrozenValueTyped {
owner: self.owner.dupe(),
value: f(self.value)?,
})
}
}