mod defer;
use defer::defer;
pub mod metacall {
use std::ffi::CString;
use std::os::raw::{
c_int,
c_long,
c_short,
c_char,
c_void,
c_float,
c_double
};
#[link(name = "metacall")] extern "C" {
fn metacall_initialize() -> c_int;
fn metacall_load_from_file(tag : *const c_char, paths : *mut *const u8, size : usize, handle : *mut *mut c_void) -> c_int;
fn metacall_function(cfn : *const c_char) -> *mut c_void;
fn metacall_destroy() -> c_int;
fn metacallfv(func : *mut c_void, args : *mut *mut c_void) -> *mut c_void;
fn metacall_value_create_short(s : c_short) -> *mut c_void;
fn metacall_value_create_int(i : c_int) -> *mut c_void;
fn metacall_value_create_long(l : c_long) -> *mut c_void;
fn metacall_value_create_float(f : c_float) -> *mut c_void;
fn metacall_value_create_double(d : c_double) -> *mut c_void;
fn metacall_value_create_bool(b : c_int) -> *mut c_void;
fn metacall_value_create_string(st: *const c_char, ln : usize) -> *mut c_void;
fn metacall_value_create_char(st: c_char) -> *mut c_void;
fn metacall_value_destroy(v : *mut c_void);
fn metacall_value_id(v : *mut c_void) -> c_int;
fn metacall_value_to_string(v: *mut c_void) -> *mut c_char;
fn metacall_value_to_char(v: *mut c_void) -> c_char;
fn metacall_value_to_short(v: *mut c_void) -> c_short;
fn metacall_value_to_int(v: *mut c_void) -> c_int;
fn metacall_value_to_long(v: *mut c_void) -> c_long;
fn metacall_value_to_bool(v: *mut c_void) -> c_int;
fn metacall_value_to_float(v: *mut c_void) -> c_float;
fn metacall_value_to_double(v: *mut c_void) -> c_double;
}
#[derive(Debug)]
pub struct Error(String);
#[derive(Debug)]
pub enum Any {
Null, Short(i16), Int(i32), Long(i64), Float(f32), Double(f64), Bool(bool), Char(char), Str(String), Array(Vec<Any>), Buffer(Vec<u8>), Pointer(Box<Any>), Function(Box<fn(Any) -> Any>) }
impl From<c_short> for Any {
fn from(val : c_short) -> Self { Any::Short(val) }
}
impl From<c_int> for Any {
fn from(val : c_int) -> Self { Any::Int(val) }
}
impl From<c_long> for Any {
fn from(val : c_long) -> Self { Any::Long(val) }
}
impl From<c_char> for Any {
fn from(val : c_char) -> Self { Any::Char(val as u8 as char) }
}
impl From<bool> for Any {
fn from(val : bool) -> Self { Any::Bool(val) }
}
impl From<c_float> for Any {
fn from(val : c_float) -> Self { Any::Float(val) }
}
impl From<c_double> for Any {
fn from(val : c_double) -> Self { Any::Double(val) }
}
pub fn initialize() -> Result<(), &'static str> {
if unsafe { metacall_initialize() } != 0 {
Err("Metacall failed to initialize")
} else {
Ok(())
}
}
pub fn load_from_file(tag : String, scripts : Vec<String>) -> Result<(), &'static str> {
let size : usize = scripts.len();
let ctag = CString::new(tag).expect("Conversion to C String failed");
let mut c_scripts : Vec<*const u8> = scripts.clone().into_iter().map(|x| x.as_bytes().as_ptr()).collect();
if unsafe { metacall_load_from_file(ctag.as_ptr(), c_scripts.as_mut_ptr(), size, std::ptr::null_mut()) } != 0 {
return Err("MetaCall failed to load script");
}
Ok(())
}
pub fn metacall(func : String, args : Vec<Any>) -> Result<Any, &'static str> {
let c_function = CString::new(func).expect("Conversion to C String failed");
let size = args.len();
unsafe {
let c_func : *mut c_void = metacall_function(c_function.as_ptr());
if c_func.is_null() {
return Err("Function Not Found")
}
let mut c_args : Vec<*mut c_void> = Vec::with_capacity(size);
for arg in args {
match arg {
Any::Short(x) => {
let a = metacall_value_create_short(x);
c_args.push(a);
},
Any::Int(x) => {
let a = metacall_value_create_int(x);
c_args.push(a);
},
Any::Long(x) => {
let a = metacall_value_create_long(x);
c_args.push(a);
},
Any::Float(x) => {
let a = metacall_value_create_float(x);
c_args.push(a);
},
Any::Double(x) => {
let a = metacall_value_create_double(x);
c_args.push(a);
},
Any::Bool(x) => {
let a = metacall_value_create_bool(x as c_int);
c_args.push(a);
},
Any::Char(x) => {
let a = metacall_value_create_char(x as c_char);
c_args.push(a);
},
Any::Str(x) => {
let st = CString::new(x.clone()).expect("can't convert to c str");
let a = metacall_value_create_string(st.as_ptr(), x.len());
c_args.push(a);
},
_ => {}
}
}
let ret : *mut c_void = metacallfv(c_func, c_args.as_mut_ptr());
let mut rt = Any::Null;
if !ret.is_null() {
match metacall_value_id(ret) {
0 => {
rt = Any::Bool(if metacall_value_to_bool(ret) != 0 { true } else { false });
},
1 => {
rt = Any::Char(metacall_value_to_char(ret) as u8 as char);
},
2 => {
rt = Any::Short(metacall_value_to_short(ret));
},
3 => {
rt = Any::Int(metacall_value_to_int(ret));
},
4 => {
rt = Any::Long(metacall_value_to_long(ret));
},
5 => {
rt = Any::Float(metacall_value_to_float(ret));
},
6 => {
rt = Any::Double(metacall_value_to_double(ret));
},
7 => {
let st = std::ffi::CStr::from_ptr(metacall_value_to_string(ret));
rt = Any::Str(String::from(st.to_str().expect("couldn't convert CStr to &str")));
},
8 => {
},
9 => {
},
10 => {
},
11 => {
},
12 => {
},
13 => {
},
14 => {
rt = Any::Null;
},
_ => {}
}
metacall_value_destroy(ret);
}
for arg in c_args {
metacall_value_destroy(arg);
}
return Ok(rt);
}
}
pub fn destroy() {
unsafe { metacall_destroy(); }
}
}
#[test]
fn test() {
let _d = defer(|| metacall::destroy());
match metacall::initialize() {
Err(e) => { println!("{}", e); panic!(); },
_ => { println!(" Hello World Metacall created ") }
}
let scripts : Vec<String> = vec!["test.mock".to_string()];
match metacall::load_from_file("mock".to_string(), scripts) {
Err(e) => { println!("{}", e); panic!(); },
_ => ()
}
match metacall::metacall("new_args".to_string(),
vec![
metacall::Any::Str("a".to_string())
])
{
Err(e) => { println!("{}", e); panic!(); },
Ok(ret) => { println!("{:?}", ret); }
}
}