Add into_rc_any and push_value to Object
This commit introduces the `into_rc_any` and `push_value` methods to the `Object` trait. The `into_rc_any` method allows for efficient, zero-cost downcasting of `Rc<Self>` to `Rc<dyn Any>`. This is a crucial step for enabling more flexible dynamic dispatch and type manipulation within the VM. The `push_value` method is implemented for series types (`ScalarSeries`, `ValueSeries`, `RecordSeries`) to allow pushing values directly onto them. This simplifies the `push` intrinsic function, removing the need for manual downcasting within its implementation. The default implementation for non-series objects panics, enforcing that only mutable series support this operation. Additionally, `ScalarValue` now includes a `from_value` method to facilitate converting `Value` back into concrete scalar types. This improves type safety and reduces boilerplate code when handling scalar conversions.
This commit is contained in:
+21
-16
@@ -48,12 +48,15 @@ impl Object for Closure {
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
fn into_rc_any(self: Rc<Self>) -> Rc<dyn Any> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CallFrame {
|
||||
stack_base: usize,
|
||||
closure: Option<Rc<dyn Object>>,
|
||||
closure: Option<Rc<Closure>>,
|
||||
}
|
||||
|
||||
pub trait VMObserver {
|
||||
@@ -154,13 +157,14 @@ impl VM {
|
||||
match result {
|
||||
Ok(Value::TailCallRequest(payload)) => {
|
||||
let (next_obj, next_args) = *payload;
|
||||
if let Some(closure) = next_obj.as_any().downcast_ref::<Closure>() {
|
||||
if let Ok(closure_rc) = next_obj.clone().into_rc_any().downcast::<Closure>() {
|
||||
self.stack.clear();
|
||||
// frames should be empty here since we popped before entering the loop
|
||||
self.frames.push(CallFrame {
|
||||
stack_base: 0,
|
||||
closure: Some(next_obj.clone()),
|
||||
closure: Some(closure_rc.clone()),
|
||||
});
|
||||
let closure = closure_rc.as_ref();
|
||||
if let Some(count) = closure.positional_count
|
||||
&& next_args.len() == count as usize
|
||||
{
|
||||
@@ -227,14 +231,15 @@ impl VM {
|
||||
closure_obj: Rc<dyn Object>,
|
||||
args: &[Value],
|
||||
) -> Result<Value, String> {
|
||||
let closure = closure_obj
|
||||
.as_any()
|
||||
.downcast_ref::<Closure>()
|
||||
.ok_or_else(|| "Object is not a closure".to_string())?;
|
||||
let closure_rc = closure_obj
|
||||
.into_rc_any()
|
||||
.downcast::<Closure>()
|
||||
.map_err(|_| "Object is not a closure".to_string())?;
|
||||
|
||||
self.stack.clear();
|
||||
self.frames.clear();
|
||||
|
||||
let closure = closure_rc.as_ref();
|
||||
if let Some(count) = closure.positional_count
|
||||
&& args.len() == count as usize
|
||||
{
|
||||
@@ -251,7 +256,7 @@ impl VM {
|
||||
|
||||
self.frames.push(CallFrame {
|
||||
stack_base: 0,
|
||||
closure: Some(closure_obj.clone()),
|
||||
closure: Some(closure_rc.clone()),
|
||||
});
|
||||
|
||||
let result = self.eval_internal(observer, &closure.exec_node);
|
||||
@@ -652,11 +657,14 @@ impl VM {
|
||||
return res;
|
||||
}
|
||||
Value::Object(obj) => {
|
||||
if let Some(closure) = obj.as_any().downcast_ref::<Closure>() {
|
||||
if let Ok(closure_rc) =
|
||||
obj.clone().into_rc_any().downcast::<Closure>()
|
||||
{
|
||||
self.frames.push(CallFrame {
|
||||
stack_base: base,
|
||||
closure: Some(obj.clone()),
|
||||
closure: Some(closure_rc.clone()),
|
||||
});
|
||||
let closure = closure_rc.as_ref();
|
||||
|
||||
let unpack_res = if let Some(count) = closure.positional_count
|
||||
&& (self.stack.len() - base) == count as usize
|
||||
@@ -915,8 +923,7 @@ impl VM {
|
||||
}
|
||||
Address::Upvalue(idx) => {
|
||||
let frame = self.frames.last().ok_or("No call frame")?;
|
||||
if let Some(closure_obj) = &frame.closure {
|
||||
let closure = closure_obj.as_any().downcast_ref::<Closure>().unwrap();
|
||||
if let Some(closure) = &frame.closure {
|
||||
let u_idx = idx.0 as usize;
|
||||
if u_idx < closure.upvalues.len() {
|
||||
Ok(closure.upvalues[u_idx].clone())
|
||||
@@ -956,8 +963,7 @@ impl VM {
|
||||
}
|
||||
Address::Upvalue(idx) => {
|
||||
let frame = self.frames.last().ok_or("No call frame")?;
|
||||
if let Some(closure_obj) = &frame.closure {
|
||||
let closure = closure_obj.as_any().downcast_ref::<Closure>().unwrap();
|
||||
if let Some(closure) = &frame.closure {
|
||||
let u_idx = idx.0 as usize;
|
||||
if u_idx < closure.upvalues.len() {
|
||||
Ok(closure.upvalues[u_idx].borrow().clone())
|
||||
@@ -1000,8 +1006,7 @@ impl VM {
|
||||
}
|
||||
Address::Upvalue(idx) => {
|
||||
let frame = self.frames.last().ok_or("No call frame")?;
|
||||
if let Some(closure_obj) = &frame.closure {
|
||||
let closure = closure_obj.as_any().downcast_ref::<Closure>().unwrap();
|
||||
if let Some(closure) = &frame.closure {
|
||||
let u_idx = idx.0 as usize;
|
||||
if u_idx < closure.upvalues.len() {
|
||||
*closure.upvalues[u_idx].borrow_mut() = value;
|
||||
|
||||
Reference in New Issue
Block a user