Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Call object for calling Dyon from Rust #501

Merged
merged 1 commit into from
Feb 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions examples/call.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#[macro_use]
extern crate dyon;

use std::sync::Arc;
use dyon::{load_str, error, Call, Module, Dfn, Lt, Type, RustObject};

fn main() {
let mut module = Module::new();

// Add functions to read `a` and `b` from `RustArgs`.
module.add(Arc::new("a_of".into()), a_of, Dfn {
lts: vec![Lt::Default],
tys: vec![Type::Any],
ret: Type::F64
});
module.add(Arc::new("b_of".into()), b_of, Dfn {
lts: vec![Lt::Default],
tys: vec![Type::Any],
ret: Type::F64
});

error(load_str("main.dyon", Arc::new(r#"
fn add_args(a: f64, b: f64) {
println("add_args:")
println(link {a" + "b" = "a + b})
}

fn add_obj(obj: {}) {
println("add_obj:")
println(link {obj.a" + "obj.b" = "obj.a + obj.b})
}

fn add_rust(obj: any) {
println("add_rust")
a := a_of(obj)
b := b_of(obj)
println(link {a" + "b" = "a + b})
}

add(a, b) = a + b

create_vec(a, b) = (a, b)

id(obj) = clone(obj)
"#.into()), &mut module));
let ref module = Arc::new(module);

let a = 20.0;
let b = 30.0;

// Call with multiple arguments.
let call = Call::new("add_args").arg(a).arg(b);
error(call.run(module));

// Call with object.
let call = Call::new("add_obj").arg(Args {a, b});
error(call.run(module));

// Call with rust object.
let call = Call::new("add_rust").rust(RustArgs {a, b});
error(call.run(module));

// Call function with return value.
let call = Call::new("add").arg(a).arg(b);
match call.run_ret::<f64>(module) {
Ok(answer) => {println!("{}", answer);}
Err(err) => {error(Err(err));}
}

// Call function that returns vec4.
let call = Call::new("create_vec").arg(a).arg(b);
match call.run_vec4::<[f64; 2]>(module) {
Ok(answer) => {println!("{:?}", answer);}
Err(err) => {error(Err(err));}
}

// Call function that returns Rust object.
let call = Call::new("id").rust(RustArgs {a, b});
match call.run_ret::<RustObject>(module) {
Ok(answer) => {println!("{:?}", answer.lock().unwrap().downcast_ref::<RustArgs>());}
Err(err) => {error(Err(err));}
}
}

struct Args {
a: f64,
b: f64,
}

dyon_obj!{Args {a, b}}

#[derive(Debug)]
struct RustArgs {
a: f64,
b: f64,
}

dyon_fn!{fn a_of(obj: RustObject) -> f64 {
let obj_guard = obj.lock().unwrap();
obj_guard.downcast_ref::<RustArgs>().unwrap().a
}}

dyon_fn!{fn b_of(obj: RustObject) -> f64 {
let obj_guard = obj.lock().unwrap();
obj_guard.downcast_ref::<RustArgs>().unwrap().b
}}
57 changes: 57 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,63 @@ pub fn run_str(source: &str, d: Arc<String>) -> Result<(), String> {
Ok(())
}

/// Used to call specific functions with arguments.
pub struct Call {
args: Vec<Variable>,
name: Arc<String>,
}

impl Call {
/// Creates a new call.
pub fn new(name: &str) -> Call {
Call {
args: vec![],
name: Arc::new(name.into())
}
}

/// Push value to argument list.
pub fn arg<T: embed::PushVariable>(mut self, val: T) -> Self {
self.args.push(val.push_var());
self
}

/// Push Vec4 to argument list.
pub fn vec4<T: embed::ConvertVec4>(mut self, val: T) -> Self {
self.args.push(Variable::Vec4(val.to()));
self
}

/// Push Rust object to argument list.
pub fn rust<T: 'static>(mut self, val: T) -> Self {
self.args.push(Variable::RustObject(Arc::new(Mutex::new(val)) as RustObject));
self
}

/// Run call without any return value.
pub fn run(&self, module: &Arc<Module>) -> Result<(), String> {
let ref mut runtime = runtime::Runtime::new();
runtime.call_str(&self.name, &self.args, module)
}

/// Run call with return value.
pub fn run_ret<T: embed::PopVariable>(&self, module: &Arc<Module>) -> Result<T, String> {
let ref mut runtime = runtime::Runtime::new();
let val = runtime.call_str_ret(&self.name, &self.args, module)?;
T::pop_var(runtime, runtime.resolve(&val))
}

/// Convert return value to a Vec4 convertible type.
pub fn run_vec4<T: embed::ConvertVec4>(&self, module: &Arc<Module>) -> Result<T, String> {
let ref mut runtime = runtime::Runtime::new();
let val = runtime.call_str_ret(&self.name, &self.args, module)?;
match runtime.resolve(&val) {
&Variable::Vec4(val) => Ok(T::from(val)),
x => Err(runtime.expected(x, "vec4"))
}
}
}

/// Loads source from file.
pub fn load(source: &str, module: &mut Module) -> Result<(), String> {
use std::fs::File;
Expand Down
43 changes: 43 additions & 0 deletions src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,14 +259,23 @@ impl Runtime {
}
}

/// Push value to stack.
pub fn push<T: embed::PushVariable>(&mut self, val: T) {
self.stack.push(val.push_var())
}

/// Push Vec4 to stack.
pub fn push_vec4<T: embed::ConvertVec4>(&mut self, val: T) {
self.stack.push(Variable::Vec4(val.to()))
}

/// Pushes Rust object to stack.
pub fn push_rust<T: 'static>(&mut self, val: T) {
use std::sync::Mutex;
use RustObject;
self.stack.push(Variable::RustObject(Arc::new(Mutex::new(val)) as RustObject))
}

pub fn expected(&self, var: &Variable, ty: &str) -> String {
let found_ty = self.typeof_var(var);
format!("{}\nExpected `{}`, found `{}`", self.stack_trace(), ty, found_ty)
Expand Down Expand Up @@ -1142,6 +1151,40 @@ impl Runtime {
}
}

/// Call function by name, returning a value.
pub fn call_str_ret(
&mut self,
function: &str,
args: &[Variable],
module: &Arc<Module>
) -> Result<Variable, String> {
use std::cell::Cell;

let name: Arc<String> = Arc::new(function.into());
match module.find_function(&name, 0) {
FnIndex::Loaded(f_index) => {
let call = ast::Call {
alias: None,
name: name.clone(),
f_index: Cell::new(FnIndex::Loaded(f_index)),
args: args.iter()
.map(|arg| ast::Expression::Variable(Range::empty(0), arg.clone()))
.collect(),
custom_source: None,
source_range: Range::empty(0),
};
match self.call(&call, &module) {
Ok((Some(val), Flow::Continue)) => Ok(val),
Err(err) => Err(err),
_ => return Err(module.error(call.source_range,
&format!("{}\nExpected something",
self.stack_trace()), self))
}
}
_ => return Err(format!("Could not find function `{}`",function))
}
}

fn swizzle(&mut self, sw: &ast::Swizzle, module: &Arc<Module>) -> Result<Flow, String> {
let v = match try!(self.expression(&sw.expr, Side::Right, module)) {
(Some(x), Flow::Continue) => x,
Expand Down