Refactor: Replace Object with StreamStorage for streams

The `Object` trait is too generic and has been causing confusion. This
commit introduces `StreamStorage` as a dedicated trait for reactive
stream types.

This change involves:

- Renaming `Object` to `StreamStorage` in relevant places.
- Updating the `Value::Object` enum variant to `Value::Stream`.
- Modifying how streams are handled in the compiler, VM, and tests to
  use the new `StreamStorage` trait.
- Adjusting example scripts and tests to reflect the change in type
  representation.
- The `StreamNode` struct now explicitly holds its `element_type`.
This commit is contained in:
2026-03-29 18:01:46 +02:00
parent a665e2c1a5
commit 10a7fcb576
9 changed files with 235 additions and 124 deletions
+16 -15
View File
@@ -192,17 +192,6 @@ impl RecordLayout {
}
}
/// 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;
/// 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>;
}
/// Read interface for all series types: indexed lookback access and type metadata.
pub trait SeriesStorage: fmt::Debug {
fn series_type_name(&self) -> &'static str;
@@ -241,6 +230,18 @@ pub trait PushableStorage: SeriesStorage {
fn push_value(&self, val: Value);
}
/// Read interface for reactive stream objects (StreamNode and derived streams).
pub trait StreamStorage: fmt::Debug {
fn stream_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 `StaticType` of the elements emitted by this stream.
fn element_type(&self) -> StaticType;
}
/// A shared sequence of values, used by both Tuples and Records.
pub type ValueList = Rc<Vec<Value>>;
@@ -287,7 +288,7 @@ pub enum Value {
Closure(Rc<Closure>), // Compiled function with captured upvalues
Quote(Rc<SyntaxNode>), // Quoted AST node (from 'expr or macro expansion)
Series(Rc<dyn SeriesStorage>), // Time series: ScalarSeries, RecordSeries, SeriesView, etc.
Object(Rc<dyn Object>), // RTL extensions: Streams and custom types
Stream(Rc<dyn StreamStorage>), // Reactive stream: StreamNode and derived streams
Cell(Rc<RefCell<Value>>), // Boxed value for captures
}
@@ -310,7 +311,7 @@ impl PartialEq for Value {
(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::Stream(a), Value::Stream(b)) => Rc::ptr_eq(a, b),
(Value::Cell(a), Value::Cell(b)) => Rc::ptr_eq(a, b),
_ => false,
}
@@ -747,7 +748,7 @@ impl Value {
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::Stream(s) => StaticType::Stream(Box::new(s.element_type())),
Value::Cell(c) => c.borrow().static_type(),
}
}
@@ -793,7 +794,7 @@ impl fmt::Display for Value {
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::Stream(s) => write!(f, "<stream:{}>", s.stream_type_name()),
Value::Cell(c) => write!(f, "{}", c.borrow()),
}
}