How to register a rust function that can accept a rhai closure? #639
Unanswered
harudagondi
asked this question in
Q&A
Replies: 3 comments 16 replies
-
fn lfo(context: NativeCallContext, fp: FnPtr) -> Result<ReturnType, Box<EvalAltResult>> {
fp.call_within_context(&context, ...)
} |
Beta Was this translation helpful? Give feedback.
7 replies
-
This works: fn phaser(x: i64, callback: impl Fn(i64) -> i64) -> i64 {
callback(x)
}
let mut engine = Engine::new();
engine.register_fn("phaser", |context: NativeCallContext, x: i64, fp: FnPtr| {
// in a real application you'd not just 'unwrap' but you'd be handling errors
let callback = Box::new(|x| fp.call_within_context(&context, (x,)).unwrap());
phaser(x, callback)
});
assert_eq!(
engine.eval::<i64>("
const FACTOR = 2;
phaser(21, |x| x * FACTOR)
")?,
42
); However, it looks like you'd want to encapsulate that closure directly into the return value (what you call the "combinator"). |
Beta Was this translation helpful? Give feedback.
6 replies
-
This somewhats recreates what you want to do with use std::cell::RefCell;
use std::rc::Rc;
type SingleNode = Rc<dyn Node>;
trait Node {
fn run(&self, x: i64) -> i64;
}
struct PhaserNode {
func: Box<dyn Fn(i64) -> i64>,
}
impl Node for PhaserNode {
fn run(&self, x: i64) -> i64 {
(self.func)(x)
}
}
// say, this is fundsp's implementation of phaser with closure parameter
// that you'd like to call
fn phaser(callback: impl Fn(i64) -> i64 + 'static) -> impl Node {
PhaserNode {
func: Box::new(callback),
}
}
let mut engine = Engine::new();
let ast = Rc::new(engine.compile(
"
const FACTOR = 2;
phaser(|x| x * FACTOR)
",
)?);
let shared_engine = Rc::new(RefCell::new(Engine::new_raw())); // dummy Engine for now
let engine2 = shared_engine.clone();
let ast2 = ast.clone();
engine.register_fn("phaser", move |fp: FnPtr| {
let engine = engine2.clone();
let ast = ast2.clone();
let callback = Box::new(move |x: i64| fp.call(&engine.borrow(), &ast, (x,)).unwrap());
Rc::new(phaser(callback)) as SingleNode
});
// replace the dummy Engine with the real one
*shared_engine.borrow_mut() = engine;
// run the script and get back a node
let cb = shared_engine.borrow().eval_ast::<SingleNode>(&ast)?;
// that node can be run
assert_eq!(cb.run(21), 42); |
Beta Was this translation helpful? Give feedback.
3 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
I am writing a library that exposes
fundsp
as a rhai module, and I don't know how to register a rust function that can accept a rhai closure. It seems that the rhai book does not mention how to do this.For example, I want to register a function that looks like this:
(
hacker32
is just a prelude, and Box is clonable)How exactly do you do this for this situation?
Beta Was this translation helpful? Give feedback.
All reactions