use std::fmt;
use std::fmt::Debug;
use std::fmt::Formatter;
use crate::eval::runtime::frame_span::FrameSpan;
use crate::eval::Arguments;
use crate::eval::Evaluator;
use crate::values::function::BoundMethodGen;
use crate::values::function::NativeAttr;
use crate::values::function::NativeAttribute;
use crate::values::function::NativeMeth;
use crate::values::function::NativeMethod;
use crate::values::FrozenRef;
use crate::values::FrozenValue;
use crate::values::FrozenValueTyped;
use crate::values::Heap;
use crate::values::Value;
use crate::values::ValueLike;
#[derive(Clone)]
pub(crate) enum UnboundValue {
Method(
FrozenValueTyped<'static, NativeMethod>,
FrozenRef<'static, dyn NativeMeth>,
),
Attr(
FrozenValueTyped<'static, NativeAttribute>,
FrozenRef<'static, dyn NativeAttr>,
),
}
impl Debug for UnboundValue {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("MaybeUnboundValue").finish_non_exhaustive()
}
}
impl UnboundValue {
#[inline]
pub(crate) fn to_frozen_value(&self) -> FrozenValue {
match self {
UnboundValue::Method(m, _) => m.to_frozen_value(),
UnboundValue::Attr(a, _) => a.to_frozen_value(),
}
}
#[inline]
pub(crate) fn bind<'v>(&self, this: Value<'v>, heap: &'v Heap) -> crate::Result<Value<'v>> {
match self {
UnboundValue::Method(m, _) => {
Ok(heap.alloc_complex(BoundMethodGen::new(this.to_value(), *m)))
}
UnboundValue::Attr(_, a) => a(this, heap),
}
}
#[inline]
pub(crate) fn invoke_method<'v>(
&self,
this: Value<'v>,
span: FrozenRef<'static, FrameSpan>,
args: &Arguments<'v, '_>,
eval: &mut Evaluator<'v, '_, '_>,
) -> crate::Result<Value<'v>> {
eval.with_call_stack(
self.to_frozen_value().to_value(),
Some(span),
|eval| match self {
UnboundValue::Method(_, m) => m.invoke(eval, this, args),
UnboundValue::Attr(_, a) => {
NativeAttribute::invoke_method_impl(&**a, this, args, eval)
}
},
)
}
}