Refactor PushableSeries trait
Introduce a new trait `PushableSeries` to distinguish objects that can have values pushed into them from those that are only readable series. This clarifies the API and allows for more precise type checking. The `Object` trait no longer has a default `push_value` implementation. Instead, `PushableSeries` now provides this functionality. `SeriesMember` has also been updated to require `PushableSeries` for RecordSeries field buffers.
This commit is contained in:
+36
-15
@@ -5,7 +5,7 @@ use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::ast::environment::Environment;
|
||||
use crate::ast::types::{Keyword, Object, RecordLayout, Series, StaticType, Value};
|
||||
use crate::ast::types::{Keyword, Object, PushableSeries, RecordLayout, Series, StaticType, Value};
|
||||
use crate::ast::types::{Purity, Signature};
|
||||
|
||||
// ============================================================================
|
||||
@@ -144,14 +144,20 @@ impl<T: ScalarValue> Object for ScalarSeries<T> {
|
||||
fn into_rc_any(self: Rc<Self>) -> Rc<dyn Any> {
|
||||
self
|
||||
}
|
||||
fn as_series(&self) -> Option<&dyn Series> {
|
||||
Some(self)
|
||||
}
|
||||
fn as_pushable_series(&self) -> Option<&dyn PushableSeries> {
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ScalarValue> PushableSeries for ScalarSeries<T> {
|
||||
fn push_value(&self, value: Value) {
|
||||
if let Some(v) = T::from_value(value) {
|
||||
self.data.borrow_mut().push(v);
|
||||
}
|
||||
}
|
||||
fn as_series(&self) -> Option<&dyn Series> {
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ScalarValue> Series for ScalarSeries<T> {
|
||||
@@ -200,12 +206,18 @@ impl Object for ValueSeries {
|
||||
fn into_rc_any(self: Rc<Self>) -> Rc<dyn Any> {
|
||||
self
|
||||
}
|
||||
fn push_value(&self, value: Value) {
|
||||
self.data.borrow_mut().push(value);
|
||||
}
|
||||
fn as_series(&self) -> Option<&dyn Series> {
|
||||
Some(self)
|
||||
}
|
||||
fn as_pushable_series(&self) -> Option<&dyn PushableSeries> {
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl PushableSeries for ValueSeries {
|
||||
fn push_value(&self, value: Value) {
|
||||
self.data.borrow_mut().push(value);
|
||||
}
|
||||
}
|
||||
|
||||
impl Series for ValueSeries {
|
||||
@@ -224,10 +236,10 @@ impl Series for ValueSeries {
|
||||
// 3. RecordSeries (SoA - Struct of Arrays)
|
||||
// ============================================================================
|
||||
|
||||
/// Marker supertrait combining `Object` and `Series` for RecordSeries field buffers.
|
||||
/// Ensures each field buffer can be stored as a typed series AND used as a dynamic object
|
||||
/// (including `push_value` via the `Object` supertrait).
|
||||
pub trait SeriesMember: Object + Series {}
|
||||
/// Marker supertrait for RecordSeries field buffers.
|
||||
/// Ensures each field buffer supports indexed access (Series), dynamic dispatch (Object),
|
||||
/// and value insertion (PushableSeries).
|
||||
pub trait SeriesMember: PushableSeries {}
|
||||
|
||||
impl SeriesMember for ScalarSeries<f64> {}
|
||||
impl SeriesMember for ScalarSeries<i64> {}
|
||||
@@ -321,6 +333,15 @@ impl Object for RecordSeries {
|
||||
fn into_rc_any(self: Rc<Self>) -> Rc<dyn Any> {
|
||||
self
|
||||
}
|
||||
fn as_series(&self) -> Option<&dyn Series> {
|
||||
Some(self)
|
||||
}
|
||||
fn as_pushable_series(&self) -> Option<&dyn PushableSeries> {
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl PushableSeries for RecordSeries {
|
||||
fn push_value(&self, value: Value) {
|
||||
if let Value::Record(_, values) = value {
|
||||
for (i, v) in values.iter().enumerate() {
|
||||
@@ -332,9 +353,6 @@ impl Object for RecordSeries {
|
||||
panic!("push to RecordSeries expects a record");
|
||||
}
|
||||
}
|
||||
fn as_series(&self) -> Option<&dyn Series> {
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Series for RecordSeries {
|
||||
@@ -622,9 +640,12 @@ pub fn register(env: &Environment) {
|
||||
let (series_val, val) = (&args[0], &args[1]);
|
||||
|
||||
if let Value::Object(obj) = series_val {
|
||||
obj.push_value(val.clone());
|
||||
if let Some(p) = obj.as_pushable_series() {
|
||||
p.push_value(val.clone());
|
||||
return Value::Void;
|
||||
}
|
||||
panic!("push expects a pushable series, got: {}", obj.type_name());
|
||||
}
|
||||
panic!("push expects a series object as the first argument")
|
||||
},
|
||||
);
|
||||
|
||||
+13
-9
@@ -176,7 +176,7 @@ impl RecordLayout {
|
||||
}
|
||||
}
|
||||
|
||||
/// Interface for custom objects (Closures, Series, Streams)
|
||||
/// Interface for custom objects (Series, Streams, SyntaxNodes, and custom extensions).
|
||||
pub trait Object: fmt::Debug {
|
||||
fn type_name(&self) -> &'static str;
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
@@ -185,17 +185,21 @@ pub trait Object: fmt::Debug {
|
||||
/// `Rc<T>` via `Rc::downcast::<T>()`. Requires `arbitrary_self_types` (stable since 1.81).
|
||||
fn into_rc_any(self: Rc<Self>) -> Rc<dyn Any>;
|
||||
|
||||
/// Pushes a value into this object if it is a mutable series.
|
||||
/// The default implementation panics — only series types override this.
|
||||
fn push_value(&self, _val: Value) {
|
||||
panic!("{} does not support push_value", self.type_name());
|
||||
}
|
||||
|
||||
/// Optional optimization: If this object behaves like a time series (indexable lookbacks),
|
||||
/// it can return a reference to its Series trait implementation.
|
||||
/// If this object supports indexed lookback access, returns a `Series` reference.
|
||||
fn as_series(&self) -> Option<&dyn Series> {
|
||||
None
|
||||
}
|
||||
|
||||
/// If this object supports pushing new values, returns a `PushableSeries` reference.
|
||||
fn as_pushable_series(&self) -> Option<&dyn PushableSeries> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Extension of `Object + Series` for types that also accept new values via `push_value`.
|
||||
/// Only series types that are mutable (ScalarSeries, ValueSeries, RecordSeries) implement this.
|
||||
pub trait PushableSeries: Object + Series {
|
||||
fn push_value(&self, val: Value);
|
||||
}
|
||||
|
||||
/// Unified interface for all series types (Local RecordSeries, SeriesViews, and future SharedSeries).
|
||||
|
||||
Reference in New Issue
Block a user