J'essaye d'appeler une fonction intégrée de Dyon ( sin ) depuis Rust:
Error: "Could not find function `sin`"
Cependant, j'obtiens
use dyon::{Module, Runtime, Variable};
use std::sync::Arc;
fn main() {
let mut dyon_runtime = Runtime::new();
let module = Module::new();
let dyon_module = Arc::new(module);
let v = dyon_runtime.call_str_ret("sin", &[Variable::f64(0.0)], &dyon_module);
match v {
Err(e) => {
eprintln!("Error: {:?}", e);
}
Ok(v) => {
println!("Called sin - result {:?}", v);
}
};
}
Que dois-je faire pour appeler correctement cette fonction?
3 Réponses :
Je ne peux pas expliquer les décisions de conception ici, mais call_str_ret gère uniquement les fonctions qui ont été chargées , pas fonctions externes ou intrinsèques .
Pour contourner le problème, vous pouvez charger une petite fonction shim qui appelle simplement la fonction appropriée:
XXX
Called sin - result F64(0.8939966636005579, None)
call_str ( ) ne s'intéresse qu'à un seul type d'appel de fonction. Je ne sais pas pourquoi ils font cela, mais une solution serait de le faire vous-même:
use dyon::{ast, Module, Runtime, Variable};
use range::Range;
use std::cell::Cell;
use std::sync::Arc;
fn main() {
let mut dyon_runtime = Runtime::new();
let module = Module::new();
let name: Arc<String> = Arc::new("sin".into());
let f_index = Cell::new(module.find_function(&name, 0));
let args = vec![ast::Expression::Variable(Box::new((
Range::empty(0),
Variable::F64(1.0, None),
)))];
let call = ast::Call {
alias: None,
name,
f_index,
args,
custom_source: None,
source_range: Range::empty(0),
};
let dyon_module = Arc::new(module);
println!("{:?}", dyon_runtime.call(&call, &dyon_module));
}
Les deux autres réponses m'ont conduit à une solution qui fonctionne parfaitement dans les deux cas:
J'ai pris le Runtime.call_str_ret et l'ai modifié pour utiliser tout résultat non-None de module.find_function . IMO, le code est en fait plus propre que la version originale dans Runtime. J'ai soumis un PR pour cela qui a été fusionné, donc les versions de Dyon après 0.40.0 auront call_str_ret fonctionnant pour les fonctions intégrées.
Si vous ne pouvez pas utiliser une version plus récente de Dyon, vous pouvez alors appliquer manuellement le correctif à partir d'ici: https: // github .com / PistonDevelopers / dyon / pull / 582 .
Vous pouvez également utiliser votre propre version de call_str_ret, comme ceci:
Called sin - result F64(0.0, None) Called sin_shim - result F64(0.0, None) Error: "Could not find function `no_such`"
Cela vous permettra d'écrire le code original sous la forme
def test_dyon_fn(
dyon_runtime: &mut Runtime
module: &Module,
fn: &str,
)
let v = call_str_ret_ex(&mut dyon_runtime, fn, &[Variable::f64(0.0)], &dyon_module);
match v {
Err(e) => {
eprintln!("Error: {:?}", e);
}
Ok(v) => {
println!("Called {:?} - result {:?}", fn, v);
}
};
fn main() {
let mut dyon_runtime = Runtime::new();
let mut module = Module::new();
let shim = Arc::new("sin_shim(x) = sin(x)".into());
dyon::load_str("main.rs", shim, &mut module).expect("Unable to load shim function");
let dyon_module = Arc::new(module);
test_dyon_fn(&mut dyon_runtime, &dyon_module, "sin");
test_dyon_fn(&mut dyon_runtime, &dyon_module, "sin_shim");
test_dyon_fn(&mut dyon_runtime, &dyon_module, "no_such");
}
Ceci imprime:
use dyon::{Module, Runtime, Variable};
use std::sync::Arc;
extern crate range;
/// Call function by name, returning a value.
pub fn call_str_ret_ex(
runtime:&mut Runtime,
function: &str,
args: &[Variable],
module: &Arc<Module>
) -> Result<Variable, String> {
use std::cell::Cell;
use range::Range;
use dyon::FnIndex;
use dyon::runtime::Flow;
use dyon::ast;
let name: Arc<String> = Arc::new(function.into());
let fn_index = module.find_function(&name, 0);
if let FnIndex::None = fn_index {
return Err(format!("Could not find function `{}`",function))
}
let call = ast::Call {
alias: None,
name: name.clone(),
f_index: Cell::new(fn_index),
args: args.iter()
.map(|arg| ast::Expression::Variable(Box::new((
Range::empty(0), arg.clone()))))
.collect(),
custom_source: None,
source_range: Range::empty(0),
};
match runtime.call(&call, &module) {
Ok((Some(val), Flow::Continue)) => Ok(val),
Err(err) => Err(err),
_ => Err("Error during call".to_owned())
}
}