use std::cell::Cell;
use derive_more::Display;
use gazebo::{any::AnyLifetime, prelude::*};
use crate as starlark;
use crate::values::{Freeze, Freezer, FrozenValue, StarlarkValue, Value, ValueLike};
#[derive(Debug, Trace, AnyLifetime, Display, NoSerialize)]
#[display(fmt = "{:?}", self)] #[repr(transparent)]
pub(crate) struct ValueCaptured<'v>(pub Cell<Option<Value<'v>>>);
#[derive(Debug, AnyLifetime, Display, NoSerialize)]
#[display(fmt = "{:?}", self)] #[repr(transparent)]
pub(crate) struct FrozenValueCaptured(Option<FrozenValue>);
impl<'v> StarlarkValue<'v> for ValueCaptured<'v> {
starlark_type!("value_captured");
}
impl<'v> StarlarkValue<'v> for FrozenValueCaptured {
starlark_type!("value_captured");
}
impl<'v> ValueCaptured<'v> {
pub(crate) fn set(&self, value: Value<'v>) {
debug_assert!(value.downcast_ref::<ValueCaptured>().is_none());
debug_assert!(value.downcast_ref::<FrozenValueCaptured>().is_none());
self.0.set(Some(value));
}
}
impl<'v> Freeze for ValueCaptured<'v> {
type Frozen = FrozenValueCaptured;
fn freeze(self, freezer: &Freezer) -> anyhow::Result<FrozenValueCaptured> {
Ok(FrozenValueCaptured(
self.0.get().into_try_map(|v| freezer.freeze(v))?,
))
}
}
pub(crate) fn value_captured_get<'v>(value_captured: Value<'v>) -> Option<Value<'v>> {
if let Some(value_captured) = value_captured.unpack_frozen() {
value_captured
.downcast_ref::<FrozenValueCaptured>()
.expect("not a ValueCaptured")
.0
.map(|v| v.to_value())
} else {
value_captured
.downcast_ref::<ValueCaptured>()
.expect("not a ValueCaptured")
.0
.get()
}
}