pub(crate) mod string;
use std::fmt;
use std::fmt::Debug;
use std::fmt::Display;
use std::fmt::Formatter;
use std::marker;
use std::ops::Deref;
use allocative::Allocative;
use dupe::Clone_;
use dupe::Copy_;
use dupe::Dupe_;
use serde::Serialize;
use starlark_map::Hashed;
use crate as starlark;
use crate::any::AnyLifetime;
use crate::any::ProvidesStaticType;
use crate::cast;
use crate::cast::transmute;
use crate::coerce::Coerce;
use crate::coerce::CoerceKey;
use crate::typing::Ty;
use crate::values::alloc_value::AllocFrozenStringValue;
use crate::values::alloc_value::AllocStringValue;
use crate::values::int::PointerI32;
use crate::values::layout::avalue::AValue;
use crate::values::layout::heap::repr::AValueRepr;
use crate::values::string::StarlarkStr;
use crate::values::type_repr::StarlarkTypeRepr;
use crate::values::AllocFrozenValue;
use crate::values::AllocValue;
use crate::values::Freeze;
use crate::values::Freezer;
use crate::values::FrozenHeap;
use crate::values::FrozenRef;
use crate::values::FrozenStringValue;
use crate::values::FrozenValue;
use crate::values::Heap;
use crate::values::StarlarkValue;
use crate::values::StringValue;
use crate::values::StringValueLike;
use crate::values::Trace;
use crate::values::Tracer;
use crate::values::UnpackValue;
use crate::values::Value;
use crate::values::ValueLike;
#[derive(Copy_, Clone_, Dupe_, ProvidesStaticType, Allocative)]
#[allocative(skip)] pub struct ValueTyped<'v, T: StarlarkValue<'v>>(Value<'v>, marker::PhantomData<&'v T>);
#[derive(Copy_, Clone_, Dupe_, ProvidesStaticType, Allocative)]
#[allocative(skip)] pub struct FrozenValueTyped<'v, T: StarlarkValue<'v>>(FrozenValue, marker::PhantomData<&'v T>);
unsafe impl<'v, T: StarlarkValue<'v>> Coerce<ValueTyped<'v, T>> for ValueTyped<'v, T> {}
unsafe impl<'v, T: StarlarkValue<'v>> CoerceKey<ValueTyped<'v, T>> for ValueTyped<'v, T> {}
unsafe impl<'v, T: StarlarkValue<'v>> Coerce<Value<'v>> for ValueTyped<'v, T> {}
unsafe impl<'v, T: StarlarkValue<'v>> CoerceKey<Value<'v>> for ValueTyped<'v, T> {}
unsafe impl<'v, T: StarlarkValue<'v>> Coerce<FrozenValueTyped<'v, T>> for FrozenValueTyped<'v, T> {}
unsafe impl<'v, T: StarlarkValue<'v>> CoerceKey<FrozenValueTyped<'v, T>>
for FrozenValueTyped<'v, T>
{
}
unsafe impl<'v, T: StarlarkValue<'v>> Coerce<Value<'v>> for FrozenValueTyped<'v, T> {}
unsafe impl<'v, T: StarlarkValue<'v>> CoerceKey<Value<'v>> for FrozenValueTyped<'v, T> {}
unsafe impl<'v, 'f, T: StarlarkValue<'f>> Trace<'v> for FrozenValueTyped<'f, T> {
fn trace(&mut self, _tracer: &Tracer<'v>) {}
}
impl<T: StarlarkValue<'static>> Freeze for FrozenValueTyped<'static, T> {
type Frozen = Self;
fn freeze(self, _freezer: &Freezer) -> anyhow::Result<Self::Frozen> {
Ok(self)
}
}
impl<'v, T: StarlarkValue<'v>> Debug for ValueTyped<'v, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("ValueTyped").field(&self.0).finish()
}
}
impl<'v, T: StarlarkValue<'v>> Debug for FrozenValueTyped<'v, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("FrozenValueTyped").field(&self.0).finish()
}
}
impl<'v, T: StarlarkValue<'v>> Display for ValueTyped<'v, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Display::fmt(&self.0, f)
}
}
impl<'v, T: StarlarkValue<'v>> Display for FrozenValueTyped<'v, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Display::fmt(&self.0, f)
}
}
impl<'v, T: StarlarkValue<'v>> Serialize for ValueTyped<'v, T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.0.serialize(serializer)
}
}
impl<'v, T: StarlarkValue<'v>> Serialize for FrozenValueTyped<'v, T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.0.serialize(serializer)
}
}
impl<'v, T: StarlarkValue<'v>> PartialEq for ValueTyped<'v, T> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<'v, T: StarlarkValue<'v>> Eq for ValueTyped<'v, T> {}
impl<'v, T: StarlarkValue<'v>> PartialEq for FrozenValueTyped<'v, T> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<'v, T: StarlarkValue<'v>> Eq for FrozenValueTyped<'v, T> {}
impl<'v, T: StarlarkValue<'v>> ValueTyped<'v, T> {
#[inline]
pub fn new(value: Value<'v>) -> Option<ValueTyped<'v, T>> {
value.downcast_ref::<T>()?;
Some(ValueTyped(value, marker::PhantomData))
}
#[inline]
pub fn new_err(value: Value<'v>) -> anyhow::Result<ValueTyped<'v, T>> {
value.downcast_ref_err::<T>()?;
Ok(ValueTyped(value, marker::PhantomData))
}
#[inline]
pub unsafe fn new_unchecked(value: Value<'v>) -> ValueTyped<'v, T> {
debug_assert!(value.downcast_ref::<T>().is_some());
ValueTyped(value, marker::PhantomData)
}
#[inline]
pub(crate) fn new_repr<A: AValue<'v, StarlarkValue = T>>(
repr: &'v AValueRepr<A>,
) -> ValueTyped<'v, T> {
ValueTyped(Value::new_repr(repr), marker::PhantomData)
}
#[inline]
pub fn to_value(self) -> Value<'v> {
self.0
}
#[inline]
pub fn as_ref(self) -> &'v T {
unsafe { self.0.downcast_ref_unchecked() }
}
pub fn hashed(self) -> crate::Result<Hashed<Self>> {
let hash = if let Some(s) = self.to_value().unpack_starlark_str() {
s.get_hash()
} else {
self.to_value().get_hash()?
};
Ok(Hashed::new_unchecked(hash, self))
}
}
impl<'v, T: StarlarkValue<'v>> FrozenValueTyped<'v, T> {
#[inline]
pub unsafe fn new_unchecked(value: FrozenValue) -> FrozenValueTyped<'v, T> {
debug_assert!(value.downcast_ref::<T>().is_some());
FrozenValueTyped(value, marker::PhantomData)
}
#[inline]
pub fn new(value: FrozenValue) -> Option<FrozenValueTyped<'v, T>> {
value.downcast_ref::<T>()?;
Some(FrozenValueTyped(value, marker::PhantomData))
}
#[inline]
pub(crate) fn new_repr<A: AValue<'v, StarlarkValue = T>>(
repr: &'v AValueRepr<A>,
) -> FrozenValueTyped<'v, T> {
let header = unsafe { cast::ptr_lifetime(&repr.header) };
FrozenValueTyped(FrozenValue::new_ptr(header, A::IS_STR), marker::PhantomData)
}
#[inline]
pub fn to_frozen_value(self) -> FrozenValue {
self.0
}
#[inline]
pub fn to_value(self) -> Value<'v> {
self.0.to_value()
}
#[inline]
pub fn to_value_typed(self) -> ValueTyped<'v, T> {
unsafe { ValueTyped::new_unchecked(self.0.to_value()) }
}
#[inline]
pub fn as_ref(self) -> &'v T {
if PointerI32::type_is_pointer_i32::<T>() {
unsafe { transmute!(&PointerI32, &T, self.0.0.unpack_pointer_i32_unchecked()) }
} else if T::static_type_id() == StarlarkStr::static_type_id() {
unsafe {
self.0
.0
.unpack_ptr_no_int_unchecked()
.unpack_header_unchecked()
.payload::<T>()
}
} else {
unsafe {
self.0
.0
.unpack_ptr_no_int_no_str_unchecked()
.unpack_header_unchecked()
.payload::<T>()
}
}
}
#[inline]
pub(crate) fn as_frozen_ref(self) -> FrozenRef<'v, T> {
FrozenRef::new(self.as_ref())
}
}
impl<'v> ValueTyped<'v, StarlarkStr> {
#[inline]
pub fn as_str(self) -> &'v str {
self.as_ref().as_str()
}
}
impl<'v> FrozenValueTyped<'v, StarlarkStr> {
#[inline]
pub fn as_str(self) -> &'v str {
self.as_ref().as_str()
}
}
unsafe impl<'v, T: StarlarkValue<'v>> Trace<'v> for ValueTyped<'v, T> {
fn trace(&mut self, tracer: &Tracer<'v>) {
tracer.trace(&mut self.0);
debug_assert!(self.0.downcast_ref::<T>().is_some());
}
}
impl<'v, T: StarlarkValue<'v>> Deref for FrozenValueTyped<'v, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
self.as_ref()
}
}
impl<'v, T: StarlarkValue<'v>> Deref for ValueTyped<'v, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
self.as_ref()
}
}
impl<'v, T: StarlarkValue<'v>> StarlarkTypeRepr for ValueTyped<'v, T> {
fn starlark_type_repr() -> Ty {
T::starlark_type_repr()
}
}
impl<'v, T: StarlarkValue<'v>> UnpackValue<'v> for ValueTyped<'v, T> {
fn expected() -> String {
T::get_type_value_static().as_str().to_owned()
}
fn unpack_value(value: Value<'v>) -> Option<Self> {
ValueTyped::new(value)
}
}
impl<'v, T: StarlarkValue<'v>> AllocValue<'v> for ValueTyped<'v, T> {
fn alloc_value(self, _heap: &'v Heap) -> Value<'v> {
self.0
}
}
impl<'v> AllocStringValue<'v> for StringValue<'v> {
fn alloc_string_value(self, _heap: &'v Heap) -> StringValue<'v> {
self
}
}
impl<'v, T: StarlarkValue<'v>> StarlarkTypeRepr for FrozenValueTyped<'v, T> {
fn starlark_type_repr() -> Ty {
T::starlark_type_repr()
}
}
impl<'v, 'f, T: StarlarkValue<'f>> AllocValue<'v> for FrozenValueTyped<'f, T> {
fn alloc_value(self, _heap: &'v Heap) -> Value<'v> {
self.0.to_value()
}
}
impl<'v> AllocStringValue<'v> for FrozenStringValue {
fn alloc_string_value(self, _heap: &'v Heap) -> StringValue<'v> {
self.to_string_value()
}
}
impl<'v, T: StarlarkValue<'v>> AllocFrozenValue for FrozenValueTyped<'v, T> {
fn alloc_frozen_value(self, _heap: &FrozenHeap) -> FrozenValue {
self.0
}
}
impl AllocFrozenStringValue for FrozenStringValue {
fn alloc_frozen_string_value(self, _heap: &FrozenHeap) -> FrozenStringValue {
self
}
}
#[cfg(test)]
mod tests {
use crate::values::int::PointerI32;
use crate::values::FrozenValue;
use crate::values::FrozenValueTyped;
#[test]
fn int() {
let v = FrozenValueTyped::<PointerI32>::new(FrozenValue::testing_new_int(17)).unwrap();
assert_eq!(17, v.as_ref().get().to_i32());
}
}