Refactor function signatures to use slices

This commit is contained in:
Michael Schimmel
2026-03-03 18:13:20 +01:00
parent 7c38dee243
commit 8c4db9a5ba
12 changed files with 262 additions and 209 deletions
+2 -2
View File
@@ -64,7 +64,7 @@ fn register_arithmetic(env: &Environment) {
let mut acc = 0.0;
for arg in args {
if let Value::Int(i) = arg {
acc += i as f64;
acc += *i as f64;
} else if let Value::Float(f) = arg {
acc += f;
}
@@ -180,7 +180,7 @@ fn register_arithmetic(env: &Environment) {
let mut acc = 1.0;
for arg in args {
if let Value::Int(i) = arg {
acc *= i as f64;
acc *= *i as f64;
} else if let Value::Float(f) = arg {
acc *= f;
}
+1 -1
View File
@@ -168,7 +168,7 @@ pub fn register(env: &Environment) {
let prng = std::rc::Rc::new(std::cell::RefCell::new(rng));
Value::Function(std::rc::Rc::new(crate::ast::types::NativeFunction {
func: std::rc::Rc::new(move |_| Value::Float(prng.borrow_mut().f64())),
func: std::rc::Rc::new(move |_args| Value::Float(prng.borrow_mut().f64())),
purity: Purity::Impure,
}))
},
+2 -2
View File
@@ -503,7 +503,7 @@ pub fn register(env: &Environment) {
ret: StaticType::Any, // In reality: Object(RecordSeries)
})),
Purity::Impure,
|args: std::vec::Vec<Value>| {
|args: &[Value]| {
if args.len() != 1 {
panic!("create-series expects exactly 1 argument (a record)");
}
@@ -525,7 +525,7 @@ pub fn register(env: &Environment) {
ret: StaticType::Void,
})),
Purity::Impure,
|args: std::vec::Vec<Value>| {
|args: &[Value]| {
if args.len() != 2 {
panic!("push-series expects exactly 2 arguments (series, record)");
}
+11 -11
View File
@@ -1,4 +1,4 @@
use crate::ast::types::Value;
use crate::ast::types::{PipeFn, Value};
use std::cell::RefCell;
use std::rc::Rc;
@@ -162,8 +162,8 @@ pub struct PipeStream {
current_values: Vec<Value>,
/// The current output signal of this pipe.
current_signal: RefCell<Option<Signal>>,
/// The executable closure representing the Lambda. Expects a Vec of arguments.
pub executor: Option<Box<dyn FnMut(Vec<Value>) -> Value>>,
/// The executable closure representing the Lambda. Expects a slice of arguments.
pub executor: Option<Box<PipeFn>>,
/// Observers of THIS pipe.
observers: RefCell<Vec<Rc<RefCell<dyn Observer>>>>,
}
@@ -172,7 +172,7 @@ impl PipeStream {
pub fn new(
name: String,
input_count: usize,
executor: Option<Box<dyn FnMut(Vec<Value>) -> Value>>,
executor: Option<Box<PipeFn>>,
) -> Self {
Self {
name,
@@ -210,8 +210,8 @@ impl Observer for PipeStream {
};
if barrier_reached {
// 1. Prepare Arguments for Lambda (Current values of all inputs)
let args = self.current_values.clone();
// 1. Prepare Arguments for Lambda (Current values of all inputs) - NO CLONE NEEDED!
let args = &self.current_values;
// 2. Execute Lambda using the encapsulated VM executor
let result = if let Some(exec) = &mut self.executor {
@@ -291,7 +291,7 @@ impl Observer for RecordPusher {
/// This keeps the VM "dumb" and moves the buffer selection logic to the RTL.
pub fn build_pipeline_node(
inputs: Vec<Rc<dyn ObservableStream>>,
executor: Box<dyn FnMut(Vec<Value>) -> Value>,
executor: Box<PipeFn>,
out_type: &StaticType,
) -> Rc<PipelineNode> {
use crate::ast::rtl::series::*;
@@ -442,7 +442,7 @@ pub fn register(env: &Environment) {
ret: StaticType::Series(Box::new(StaticType::Record(ohlc_layout.clone()))),
})),
Purity::Impure, // Modifies global generator registry
move |args: std::vec::Vec<Value>| {
move |args: &[Value]| {
if args.len() != 2 {
panic!("create-random-ohlc expects exactly 2 arguments (seed, limit)");
}
@@ -527,7 +527,7 @@ pub fn register(env: &Environment) {
ret: StaticType::Any, // Returns StreamNode
})),
Purity::Impure,
move |args: std::vec::Vec<Value>| {
move |args: &[Value]| {
if args.len() != 1 {
panic!("create-ticker expects exactly 1 argument (the condition closure)");
}
@@ -550,7 +550,7 @@ pub fn register(env: &Environment) {
// 3. Create generator
let generator = move || -> bool {
match ticker_vm.run_with_args(my_closure.clone(), vec![]) {
match ticker_vm.run_with_args(my_closure.clone(), &[]) {
Ok(Value::Bool(b)) => {
if b {
// Ticker pulses with a simple `true` value or `Void`
@@ -578,7 +578,7 @@ pub fn register(env: &Environment) {
#[cfg(test)]
mod tests {
use super::*;
use crate::ast::types::Value;
use crate::ast::types::{PipeFn, Value};
#[test]
fn test_root_to_pipe_flow() {
+9 -9
View File
@@ -53,10 +53,10 @@ impl TypeRegistry {
pub fn create_factory<T, F>(factory_func: F) -> Value
where
T: Scriptable,
F: Fn(Vec<Value>) -> Result<T, String> + 'static,
F: Fn(&[Value]) -> Result<T, String> + 'static,
{
// The factory is a script function that calls the Rust factory, gets T, then wraps it.
let closure = move |args: Vec<Value>| -> Value {
let closure = move |args: &[Value]| -> Value {
match factory_func(args) {
Ok(instance) => instance.wrap(),
Err(msg) => {
@@ -90,7 +90,7 @@ impl RecordBuilder {
pub fn method<F>(mut self, name: &str, func: F) -> Self
where
F: Fn(Vec<Value>) -> Value + 'static,
F: Fn(&[Value]) -> Value + 'static,
{
let key = Keyword::intern(name);
self.fields
@@ -101,9 +101,9 @@ impl RecordBuilder {
// Helper for methods that return Result (propagating panics for now)
pub fn method_checked<F>(self, name: &str, func: F) -> Self
where
F: Fn(Vec<Value>) -> Result<Value, String> + 'static,
F: Fn(&[Value]) -> Result<Value, String> + 'static,
{
let closure = move |args: Vec<Value>| match func(args) {
let closure = move |args: &[Value]| match func(args) {
Ok(v) => v,
Err(e) => panic!("Method call error: {}", e),
};
@@ -218,7 +218,7 @@ mod tests {
let greet_fn = &values[idx];
if let Value::Function(f) = greet_fn {
let res = (f.func)(vec![]);
let res = (f.func)(&[]);
if let Value::Text(s) = res {
assert_eq!(&*s, "Hello Alice");
} else {
@@ -234,7 +234,7 @@ mod tests {
#[test]
fn test_factory() {
let factory_val = TypeRegistry::create_factory(|args: Vec<Value>| {
let factory_val = TypeRegistry::create_factory(|args: &[Value]| {
if args.len() != 2 {
return Err("Expected 2 args".to_string());
}
@@ -250,13 +250,13 @@ mod tests {
});
if let Value::Function(f) = factory_val {
let instance = (f.func)(vec![Value::Text("Bob".into()), Value::Int(40)]);
let instance = (f.func)(&[Value::Text("Bob".into()), Value::Int(40)]);
if let Value::Record(layout, values) = instance {
let idx = layout.index_of(Keyword::intern("greet")).unwrap();
let greet_fn = &values[idx];
if let Value::Function(gf) = greet_fn {
let res = (gf.func)(vec![]);
let res = (gf.func)(&[]);
if let Value::Text(s) = res {
assert_eq!(&*s, "Hello Bob");
} else {