Refactor series types and value enum
This commit refactors the way series are represented and handled within the AST. Key changes include: - Introducing `SeriesStorage` and `PushableStorage` traits to provide a more unified and type-safe interface for series data. - Renaming `Object` trait and its methods to clarify that it's for RTL extensions other than series (like Streams). - Updating the `Value` enum to have a distinct `Series` variant, separating it from `Object`. - Adjusting various parts of the `VM` and `register` functions to work with the new series traits and `Value::Series` variant. This change aims to improve the type system's clarity and safety when dealing with series data, aligning with Rust's best practices for trait design.
This commit is contained in:
+29
-19
@@ -177,7 +177,8 @@ impl RecordLayout {
|
||||
}
|
||||
}
|
||||
|
||||
/// Interface for custom objects (Series, Streams, SyntaxNodes, and custom extensions).
|
||||
/// Interface for custom RTL objects (Streams and custom extensions).
|
||||
/// For series data, use `Value::Series` with the `SeriesStorage` trait instead.
|
||||
pub trait Object: fmt::Debug {
|
||||
fn type_name(&self) -> &'static str;
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
@@ -185,26 +186,20 @@ pub trait Object: fmt::Debug {
|
||||
/// Converts `Rc<Self>` into `Rc<dyn Any>`, enabling zero-copy downcasting to a concrete
|
||||
/// `Rc<T>` via `Rc::downcast::<T>()`. Requires `arbitrary_self_types` (stable since 1.81).
|
||||
fn into_rc_any(self: Rc<Self>) -> Rc<dyn Any>;
|
||||
|
||||
/// 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);
|
||||
}
|
||||
/// Read interface for all series types: indexed lookback access and type metadata.
|
||||
pub trait SeriesStorage: fmt::Debug {
|
||||
fn series_type_name(&self) -> &'static str;
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
|
||||
/// Converts `Rc<Self>` into `Rc<dyn Any>` for zero-copy concrete downcast.
|
||||
fn into_rc_any(self: Rc<Self>) -> Rc<dyn Any>;
|
||||
|
||||
/// Returns the inner `StaticType` of this series' elements
|
||||
/// (e.g. `StaticType::Float` for a float series, `StaticType::Record(layout)` for a record series).
|
||||
fn inner_static_type(&self) -> StaticType;
|
||||
|
||||
/// Unified interface for all series types (Local RecordSeries, SeriesViews, and future SharedSeries).
|
||||
pub trait Series {
|
||||
/// Gets the value at the specified lookback index (0 = newest).
|
||||
fn get_item(&self, index: usize) -> Option<Value>;
|
||||
|
||||
@@ -218,6 +213,17 @@ pub trait Series {
|
||||
fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
/// Returns a write interface if this series supports push. Read-only series return `None`.
|
||||
fn as_pushable(&self) -> Option<&dyn PushableStorage> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Write interface for mutable series (ScalarSeries, ValueSeries, RecordSeries).
|
||||
/// Obtained via `SeriesStorage::as_pushable()`.
|
||||
pub trait PushableStorage: SeriesStorage {
|
||||
fn push_value(&self, val: Value);
|
||||
}
|
||||
|
||||
/// A shared sequence of values, used by both Tuples and Records.
|
||||
@@ -265,7 +271,8 @@ pub enum Value {
|
||||
Function(Rc<NativeFunction>),
|
||||
Closure(Rc<Closure>), // Compiled function with captured upvalues
|
||||
Quote(Rc<SyntaxNode>), // Quoted AST node (from 'expr or macro expansion)
|
||||
Object(Rc<dyn Object>), // RTL extensions: Series, Streams, and custom types
|
||||
Series(Rc<dyn SeriesStorage>), // Time series: ScalarSeries, RecordSeries, SeriesView, etc.
|
||||
Object(Rc<dyn Object>), // RTL extensions: Streams and custom types
|
||||
Cell(Rc<RefCell<Value>>), // Boxed value for captures
|
||||
}
|
||||
|
||||
@@ -287,6 +294,7 @@ impl PartialEq for Value {
|
||||
(Value::Function(a), Value::Function(b)) => Rc::ptr_eq(a, b),
|
||||
(Value::Closure(a), Value::Closure(b)) => Rc::ptr_eq(a, b),
|
||||
(Value::Quote(a), Value::Quote(b)) => Rc::ptr_eq(a, b),
|
||||
(Value::Series(a), Value::Series(b)) => Rc::ptr_eq(a, b),
|
||||
(Value::Object(a), Value::Object(b)) => Rc::ptr_eq(a, b),
|
||||
(Value::Cell(a), Value::Cell(b)) => Rc::ptr_eq(a, b),
|
||||
_ => false,
|
||||
@@ -645,6 +653,7 @@ impl Value {
|
||||
Value::Function(_) => StaticType::Any, // Dynamic function
|
||||
Value::Closure(_) => StaticType::Object("closure"),
|
||||
Value::Quote(_) => StaticType::Object("ast-node"),
|
||||
Value::Series(s) => StaticType::Series(Box::new(s.inner_static_type())),
|
||||
Value::Object(o) => StaticType::Object(o.type_name()),
|
||||
Value::Cell(c) => c.borrow().static_type(),
|
||||
}
|
||||
@@ -690,6 +699,7 @@ impl fmt::Display for Value {
|
||||
Value::Function(f_meta) => write!(f, "<native fn, {:?}>", f_meta.purity),
|
||||
Value::Closure(_) => write!(f, "<closure>"),
|
||||
Value::Quote(_) => write!(f, "<ast-node>"),
|
||||
Value::Series(s) => write!(f, "<series:{}>", s.series_type_name()),
|
||||
Value::Object(o) => write!(f, "<{:?}>", o),
|
||||
Value::Cell(c) => write!(f, "{}", c.borrow()),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user