feat: Add SharedValueSeries and PipelineNode
Introduces `SharedValueSeries` for read-only access to generic `Value` buffers, and `PipelineNode` which combines an `ObservableStream` with a `Series` view. This is a foundational step for implementing the `pipe` operator.
This commit is contained in:
+55
-7
@@ -369,15 +369,63 @@ impl VM {
|
||||
}
|
||||
}
|
||||
BoundKind::Pipe { inputs, lambda } => {
|
||||
// To be implemented in next step:
|
||||
// 1. Create PipeStream
|
||||
// 2. Link with RootStream and Inputs
|
||||
// 3. Create and return SharedSeries
|
||||
use crate::ast::rtl::streams::{PipelineNode, PipeStream, StreamNode, ValuePusher, ObservableStream};
|
||||
use crate::ast::rtl::series::{RingBuffer, SharedValueSeries};
|
||||
|
||||
let mut obs_streams = Vec::new();
|
||||
for input in inputs {
|
||||
self.eval_internal(obs, input)?;
|
||||
let val = self.eval_internal(obs, input)?;
|
||||
if let Value::Object(obj) = val {
|
||||
if let Some(s) = obj.as_any().downcast_ref::<StreamNode>() {
|
||||
obs_streams.push(s.inner.clone());
|
||||
} else if let Some(p) = obj.as_any().downcast_ref::<PipelineNode>() {
|
||||
obs_streams.push(p.stream.clone());
|
||||
} else {
|
||||
return Err(format!("Pipe input must be a stream, found {}", obj.type_name()));
|
||||
}
|
||||
} else {
|
||||
return Err("Pipe input must be an object (stream)".to_string());
|
||||
}
|
||||
}
|
||||
self.eval_internal(obs, lambda)?;
|
||||
Ok(Value::Void)
|
||||
|
||||
let lambda_val = self.eval_internal(obs, lambda)?;
|
||||
let lambda_obj = if let Value::Object(obj) = lambda_val {
|
||||
obj
|
||||
} else {
|
||||
return Err("Pipe lambda must be a function/closure".to_string());
|
||||
};
|
||||
|
||||
let pipe = Rc::new(RefCell::new(PipeStream::new(
|
||||
"pipe".to_string(),
|
||||
inputs.len(),
|
||||
Some(lambda_obj)
|
||||
)));
|
||||
|
||||
for stream in obs_streams {
|
||||
stream.add_observer(pipe.clone() as Rc<RefCell<dyn crate::ast::rtl::streams::Observer>>);
|
||||
}
|
||||
|
||||
// Create the data buffer and pusher for the pipe's output
|
||||
let buffer = Rc::new(RefCell::new(RingBuffer::<Value>::new()));
|
||||
let pusher = Rc::new(RefCell::new(ValuePusher {
|
||||
buffer: buffer.clone(),
|
||||
lookback: Some(100), // Default lookback for now
|
||||
}));
|
||||
|
||||
// The pipe pushes to the buffer
|
||||
pipe.borrow().add_observer(pusher);
|
||||
|
||||
// Create the Series view for script access
|
||||
let series = Rc::new(SharedValueSeries {
|
||||
buffer,
|
||||
});
|
||||
|
||||
let node = Rc::new(PipelineNode {
|
||||
stream: pipe,
|
||||
series,
|
||||
});
|
||||
|
||||
Ok(Value::Object(node))
|
||||
}
|
||||
BoundKind::Block { exprs } => {
|
||||
let mut last = Value::Void;
|
||||
|
||||
Reference in New Issue
Block a user