use std::{
any::TypeId,
cmp::Ordering,
fmt::{Debug, Display, Write},
};
use derive_more::Display;
use erased_serde::Serialize;
use gazebo::any::AnyLifetime;
use crate::{
self as starlark,
collections::StarlarkHasher,
environment::Methods,
eval::{Arguments, Evaluator},
values::{
docs::DocItem, error::ControlError, function::FUNCTION_TYPE, Freeze, FrozenStringValue,
Heap, Trace, Value, ValueError,
},
};
pub trait ComplexValue<'v>: StarlarkValue<'v> + Trace<'v> + Freeze
where
<Self as Freeze>::Frozen: StarlarkValue<'static>,
{
}
impl<'v, V> ComplexValue<'v> for V
where
V: StarlarkValue<'v> + Trace<'v> + Freeze,
<V as Freeze>::Frozen: StarlarkValue<'static>,
{
}
#[derive(Debug, AnyLifetime, Display, NoSerialize)]
#[display(fmt = "NoSimpleValue")] pub enum NoSimpleValue {}
impl<'v> StarlarkValue<'v> for NoSimpleValue {
starlark_type!("no_simple_value");
}
pub trait StarlarkValue<'v>: 'v + AnyLifetime<'v> + Debug + Display + Serialize {
fn get_type(&self) -> &'static str;
fn get_type_value_static() -> FrozenStringValue
where
Self: Sized;
#[doc(hidden)]
fn is_special() -> bool
where
Self: Sized,
{
false
}
fn matches_type(&self, ty: &str) -> bool {
self.get_type() == ty
}
fn get_methods(&self) -> Option<&'static Methods> {
None
}
fn documentation(&self) -> Option<DocItem> {
self.get_methods().map(|methods| methods.documentation())
}
fn collect_repr(&self, collector: &mut String) {
write!(collector, "{}", self).unwrap()
}
fn collect_repr_cycle(&self, collector: &mut String) {
write!(collector, "<{}...>", self.get_type()).unwrap()
}
fn name_for_call_stack(&self, me: Value<'v>) -> String {
me.to_repr()
}
fn to_bool(&self) -> bool {
true
}
fn to_int(&self) -> anyhow::Result<i32> {
ValueError::unsupported(self, "int()")
}
fn write_hash(&self, hasher: &mut StarlarkHasher) -> anyhow::Result<()> {
if self.get_type() == FUNCTION_TYPE {
let _ = hasher;
Ok(())
} else {
Err(ControlError::NotHashableValue(self.get_type().to_owned()).into())
}
}
fn extra_memory(&self) -> usize {
0
}
fn equals(&self, _other: Value<'v>) -> anyhow::Result<bool> {
Ok(false)
}
fn compare(&self, other: Value<'v>) -> anyhow::Result<Ordering> {
ValueError::unsupported_with(self, "compare", other)
}
fn invoke(
&self,
_me: Value<'v>,
_args: &Arguments<'v, '_>,
_eval: &mut Evaluator<'v, '_>,
) -> anyhow::Result<Value<'v>> {
ValueError::unsupported(self, "call()")
}
#[doc(hidden)]
fn invoke_method(
&self,
_me: Value<'v>,
_this: Value<'v>,
_args: &Arguments<'v, '_>,
_eval: &mut Evaluator<'v, '_>,
) -> anyhow::Result<Value<'v>> {
unreachable!("invoke_method should only be invoked for method or attribute");
}
fn at(&self, index: Value<'v>, _heap: &'v Heap) -> anyhow::Result<Value<'v>> {
ValueError::unsupported_with(self, "[]", index)
}
fn slice(
&self,
_start: Option<Value<'v>>,
_stop: Option<Value<'v>>,
_stride: Option<Value<'v>>,
_heap: &'v Heap,
) -> anyhow::Result<Value<'v>> {
ValueError::unsupported(self, "[::]")
}
fn iterate<'a>(
&'a self,
_heap: &'v Heap,
) -> anyhow::Result<Box<dyn Iterator<Item = Value<'v>> + 'a>>
where
'v: 'a,
{
ValueError::unsupported(self, "(iter)")
}
fn with_iterator(
&self,
heap: &'v Heap,
f: &mut dyn FnMut(&mut dyn Iterator<Item = Value<'v>>) -> anyhow::Result<()>,
) -> anyhow::Result<()> {
f(&mut *self.iterate(heap)?)
}
fn length(&self) -> anyhow::Result<i32> {
ValueError::unsupported(self, "len()")
}
fn get_attr(&self, _attribute: &str, _heap: &'v Heap) -> Option<Value<'v>> {
None
}
fn has_attr(&self, _attribute: &str) -> bool {
false
}
fn dir_attr(&self) -> Vec<String> {
Vec::new()
}
fn is_in(&self, other: Value<'v>) -> anyhow::Result<bool> {
ValueError::unsupported_owned(other.get_type(), "in", Some(self.get_type()))
}
fn plus(&self, _heap: &'v Heap) -> anyhow::Result<Value<'v>> {
ValueError::unsupported(self, "+")
}
fn minus(&self, _heap: &'v Heap) -> anyhow::Result<Value<'v>> {
ValueError::unsupported(self, "-")
}
fn radd(&self, _lhs: Value<'v>, _heap: &'v Heap) -> Option<anyhow::Result<Value<'v>>> {
None
}
fn add(&self, _rhs: Value<'v>, _heap: &'v Heap) -> Option<anyhow::Result<Value<'v>>> {
None
}
fn sub(&self, other: Value<'v>, _heap: &'v Heap) -> anyhow::Result<Value<'v>> {
ValueError::unsupported_with(self, "-", other)
}
fn mul(&self, other: Value<'v>, _heap: &'v Heap) -> anyhow::Result<Value<'v>> {
ValueError::unsupported_with(self, "*", other)
}
fn div(&self, other: Value<'v>, _heap: &'v Heap) -> anyhow::Result<Value<'v>> {
ValueError::unsupported_with(self, "/", other)
}
fn percent(&self, other: Value<'v>, _heap: &'v Heap) -> anyhow::Result<Value<'v>> {
ValueError::unsupported_with(self, "%", other)
}
fn floor_div(&self, other: Value<'v>, _heap: &'v Heap) -> anyhow::Result<Value<'v>> {
ValueError::unsupported_with(self, "//", other)
}
fn bit_and(&self, other: Value<'v>, _heap: &'v Heap) -> anyhow::Result<Value<'v>> {
ValueError::unsupported_with(self, "&", other)
}
fn bit_or(&self, other: Value<'v>, _heap: &'v Heap) -> anyhow::Result<Value<'v>> {
ValueError::unsupported_with(self, "|", other)
}
fn bit_xor(&self, other: Value<'v>, _heap: &'v Heap) -> anyhow::Result<Value<'v>> {
ValueError::unsupported_with(self, "^", other)
}
fn bit_not(&self, _heap: &'v Heap) -> anyhow::Result<Value<'v>> {
ValueError::unsupported(self, "~")
}
fn left_shift(&self, other: Value<'v>, _heap: &'v Heap) -> anyhow::Result<Value<'v>> {
ValueError::unsupported_with(self, "<<", other)
}
fn right_shift(&self, other: Value<'v>, _heap: &'v Heap) -> anyhow::Result<Value<'v>> {
ValueError::unsupported_with(self, ">>", other)
}
fn export_as(&self, _variable_name: &str, _eval: &mut Evaluator<'v, '_>) {
}
fn set_at(&self, _index: Value<'v>, _new_value: Value<'v>) -> anyhow::Result<()> {
Err(ValueError::CannotMutateImmutableValue.into())
}
fn set_attr(&self, attribute: &str, _new_value: Value<'v>) -> anyhow::Result<()> {
ValueError::unsupported(self, &format!(".{}=", attribute))
}
}
pub(crate) trait StarlarkValueDyn<'v>: 'v + Serialize {
fn static_type_of_value(&self) -> TypeId;
fn as_debug(&self) -> &dyn Debug;
fn as_display(&self) -> &dyn Display;
fn value_as_dyn_any(&self) -> &dyn AnyLifetime<'v>;
fn get_type(&self) -> &'static str;
fn get_type_value(&self) -> FrozenStringValue;
fn matches_type(&self, _ty: &str) -> bool;
fn get_methods(&self) -> Option<&'static Methods>;
fn documentation(&self) -> Option<DocItem>;
fn collect_repr(&self, _collector: &mut String);
fn collect_repr_cycle(&self, _collector: &mut String);
fn name_for_call_stack(&self, me: Value<'v>) -> String;
fn to_bool(&self) -> bool;
fn to_int(&self) -> anyhow::Result<i32>;
fn write_hash(&self, hasher: &mut StarlarkHasher) -> anyhow::Result<()>;
fn extra_memory(&self) -> usize;
fn equals(&self, _other: Value<'v>) -> anyhow::Result<bool>;
fn compare(&self, _other: Value<'v>) -> anyhow::Result<Ordering>;
fn invoke(
&self,
_me: Value<'v>,
_args: &Arguments<'v, '_>,
_eval: &mut Evaluator<'v, '_>,
) -> anyhow::Result<Value<'v>>;
fn invoke_method(
&self,
me: Value<'v>,
this: Value<'v>,
args: &Arguments<'v, '_>,
eval: &mut Evaluator<'v, '_>,
) -> anyhow::Result<Value<'v>>;
fn at(&self, _index: Value<'v>, _heap: &'v Heap) -> anyhow::Result<Value<'v>>;
fn slice(
&self,
_start: Option<Value<'v>>,
_stop: Option<Value<'v>>,
_stride: Option<Value<'v>>,
_heap: &'v Heap,
) -> anyhow::Result<Value<'v>>;
fn iterate<'a>(
&'a self,
_heap: &'v Heap,
) -> anyhow::Result<Box<dyn Iterator<Item = Value<'v>> + 'a>>
where
'v: 'a;
fn with_iterator(
&self,
_heap: &'v Heap,
_f: &mut dyn FnMut(&mut dyn Iterator<Item = Value<'v>>) -> anyhow::Result<()>,
) -> anyhow::Result<()>;
fn length(&self) -> anyhow::Result<i32>;
fn get_attr(&self, _attribute: &str, _heap: &'v Heap) -> Option<Value<'v>>;
fn has_attr(&self, _attribute: &str) -> bool;
fn dir_attr(&self) -> Vec<String>;
fn is_in(&self, _other: Value<'v>) -> anyhow::Result<bool>;
fn plus(&self, _heap: &'v Heap) -> anyhow::Result<Value<'v>>;
fn minus(&self, _heap: &'v Heap) -> anyhow::Result<Value<'v>>;
fn radd(&self, _lhs: Value<'v>, _heap: &'v Heap) -> Option<anyhow::Result<Value<'v>>>;
fn add(&self, _rhs: Value<'v>, _heap: &'v Heap) -> Option<anyhow::Result<Value<'v>>>;
fn sub(&self, _other: Value<'v>, _heap: &'v Heap) -> anyhow::Result<Value<'v>>;
fn mul(&self, _other: Value<'v>, _heap: &'v Heap) -> anyhow::Result<Value<'v>>;
fn percent(&self, _other: Value<'v>, _heap: &'v Heap) -> anyhow::Result<Value<'v>>;
fn div(&self, _other: Value<'v>, _heap: &'v Heap) -> anyhow::Result<Value<'v>>;
fn floor_div(&self, _other: Value<'v>, _heap: &'v Heap) -> anyhow::Result<Value<'v>>;
fn bit_and(&self, _other: Value<'v>, heap: &'v Heap) -> anyhow::Result<Value<'v>>;
fn bit_or(&self, _other: Value<'v>, _heap: &'v Heap) -> anyhow::Result<Value<'v>>;
fn bit_xor(&self, _other: Value<'v>, heap: &'v Heap) -> anyhow::Result<Value<'v>>;
fn bit_not(&self, heap: &'v Heap) -> anyhow::Result<Value<'v>>;
fn left_shift(&self, _other: Value<'v>, heap: &'v Heap) -> anyhow::Result<Value<'v>>;
fn right_shift(&self, _other: Value<'v>, heap: &'v Heap) -> anyhow::Result<Value<'v>>;
fn export_as(&self, _variable_name: &str, _eval: &mut Evaluator<'v, '_>);
fn set_at(&self, _index: Value<'v>, _new_value: Value<'v>) -> anyhow::Result<()>;
fn set_attr(&self, _attribute: &str, _new_value: Value<'v>) -> anyhow::Result<()>;
}