Refactor: Create typed series factory function

Introduces `create_typed_series` to centralize series creation logic.
This function dispatches on `StaticType` to select the appropriate
`SeriesStorage` implementation,
improving code reuse and maintainability within the series RTL.

The `SeriesHook` compiler hook is updated to use this new factory
function.
Additionally, new tests have been added to `rtl/streams.rs` and
`tests/pipeline.rs`
to specifically cover the behavior of `pipe-buffered`, focusing on its
fill gate
mechanism and multi-input handling.
This commit is contained in:
2026-03-30 10:38:28 +02:00
parent 6628941a50
commit 141ae36ede
3 changed files with 174 additions and 42 deletions
+61
View File
@@ -145,3 +145,64 @@ fn test_pipeline_optional_type() {
panic!("Expected a Stream(StreamNode)");
}
}
/// Verifies that `pipe-buffered` accumulates values into Series and only fires
/// the lambda once all series have reached the lookback depth (fill gate).
/// Lambda parameters must be Series objects, not individual values.
#[test]
fn test_pipe_buffered_fill_gate() {
let env = Environment::new();
// create-random-ohlc produces 10 ticks. With lookback 3, the lambda
// fires from tick 3 onwards (8 times). Each call returns the difference
// between the current and previous close: (.close (bars 0)) - (.close (bars 1))
let source = "(do
(def ohlc (create-random-ohlc 42 10))
(def result (pipe-buffered 3 [ohlc]
(fn [bars]
(- (.close (bars 0)) (.close (bars 1))))))
result
)";
let res = env.run_script(source);
assert!(res.is_ok(), "pipe-buffered script failed: {:?}", res.err());
let val = res.unwrap();
if let Value::Stream(s) = val {
assert_eq!(s.stream_type_name(), "stream");
} else {
panic!("Expected Stream from pipe-buffered, got: {:?}", val);
}
}
/// Verifies that pipe-buffered with multiple inputs waits for all series to fill.
#[test]
fn test_pipe_buffered_multi_input() {
let env = Environment::new();
let source = "(do
(def src1 (create-random-ohlc 42 10))
(def src2 (create-random-ohlc 99 10))
(def result (pipe-buffered 2 [src1 src2]
(fn [a b]
(+ (.close (a 0)) (.close (b 0))))))
result
)";
let res = env.run_script(source);
assert!(res.is_ok(), "pipe-buffered multi-input failed: {:?}", res.err());
}
/// Verifies that pipe-buffered lambda params are typed as Series, not raw values.
/// The arg hint resolver must wrap inner types in Series<T>.
#[test]
fn test_pipe_buffered_lambda_params_are_series() {
let env = Environment::new();
let source = "(do
(def ohlc (create-random-ohlc 42 5))
(pipe-buffered 3 [ohlc] (fn [bars] (.close (bars 0))))
)";
let dump = env.dump_ast(source).expect("dump_ast failed");
// Lambda param should be Series<Record>, not just Record or Any
assert!(
dump.contains("series<"),
"Lambda param should be typed as Series, not raw value.\nDump:\n{dump}"
);
}