#[allow(unused)]
#[cfg(test)]
mod tests {
use std::{
ffi::{CStr, CString, c_char, c_void},
ptr,
sync::Arc,
};
use pixelscript::{
lua::LuaScripting,
shared::{PixelScript, PtrMagic, object::pxs_PixelObject, pxs_Runtime, var::{pxs_Var, pxs_VarT}},
*,
};
macro_rules! create_raw_string {
($rstr:expr) => {{ CString::new($rstr).unwrap().into_raw() }};
}
macro_rules! free_raw_string {
($rptr:expr) => {{
if !$rptr.is_null() {
unsafe {
let _ = std::ffi::CString::from_raw($rptr);
}
}
}};
}
struct Diary {
owner: String,
items: Vec<String>,
}
impl Diary {
pub fn new(owner: String) -> Self {
Diary {
owner,
items: vec![],
}
}
}
impl PtrMagic for Diary {}
pub extern "C" fn free_diary(ptr: *mut c_void) {
let _ = unsafe { Diary::from_raw(ptr as *mut Diary) };
}
extern "C" fn add_item(args: pxs_VarT) -> pxs_VarT {
unsafe {
let pixel_object_var = pxs_listget(args, 1);
let host_ptr = pxs_gethost(pxs_listget(args, 0), pixel_object_var);
let d = Diary::from_borrow(host_ptr as *mut Diary);
let item = pxs_listget(args, 2);
let contents = pxs_getstring(item);
let str = own_string!(contents);
d.items.push(str);
pxs_newnull()
}
}
extern "C" fn new_diary(args: pxs_VarT) -> pxs_VarT {
unsafe {
let p_name = pxs_Var::from_borrow(pxs_listget(args, 1));
let p_name = p_name.get_string().unwrap();
let p = Diary::new(p_name.clone());
let typename = create_raw_string!("Diary");
let ptr = Diary::into_raw(p) as *mut c_void;
let pixel_object = pxs_newobject(ptr, free_diary, typename);
let add_item_raw = create_raw_string!("add_item");
pxs_object_add_reffunc(pixel_object, add_item_raw, add_item);
let var = pxs_newhost(pixel_object);
free_raw_string!(add_item_raw);
free_raw_string!(typename);
var
}
}
struct Person {
name: String,
}
impl Person {
pub fn new(n_name: String) -> Self {
Person { name: n_name }
}
pub fn set_name(&mut self, n_name: String) {
self.name = n_name;
}
pub fn get_name(&self) -> String {
self.name.clone()
}
}
impl PtrMagic for Person {}
pub extern "C" fn free_person(ptr: *mut c_void) {
let _ = unsafe { Person::from_raw(ptr as *mut Person) };
}
pub extern "C" fn set_name(
args: *mut pxs_Var,
) -> *mut pxs_Var {
unsafe {
let pixel_object_var = pxs_listget(args, 1);
let host_ptr = pxs_gethost(pxs_listget(args, 0), pixel_object_var);
let p = Person::from_borrow(host_ptr as *mut Person);
let name = {
let first_arg = pxs_Var::from_borrow(pxs_listget(args, 2));
if first_arg.is_string() {
first_arg
} else {
pxs_Var::from_borrow(pxs_listget(args, 3))
}
};
p.set_name(name.get_string().unwrap().clone());
pxs_Var::into_raw(pxs_Var::new_null())
}
}
pub extern "C" fn get_name(
args: *mut pxs_Var,
) -> *mut pxs_Var {
unsafe {
let pixel_object_var = pxs_listget(args, 1);
let host_ptr = pxs_gethost(pxs_listget(args, 0), pixel_object_var);
let p = Person::from_borrow(host_ptr as *mut Person);
pxs_Var::new_string(p.get_name().clone()).into_raw()
}
}
pub extern "C" fn new_person(
args: *mut pxs_Var,
) -> *mut pxs_Var {
unsafe {
let p_name = pxs_Var::from_borrow(pxs_listget(args, 1));
let p_name = p_name.get_string().unwrap();
let p = Person::new(p_name.clone());
let type_name = create_raw_string!("Person");
let ptr = Person::into_raw(p) as *mut c_void;
let pixel_object = pxs_newobject(ptr, free_person, type_name);
let set_name_raw = create_raw_string!("set_name");
let get_name_raw = create_raw_string!("get_name");
pxs_object_addfunc(pixel_object, set_name_raw, set_name);
pxs_object_addfunc(pixel_object, get_name_raw, get_name);
let var = pxs_newhost(pixel_object);
free_raw_string!(set_name_raw);
free_raw_string!(get_name_raw);
free_raw_string!(type_name);
var
}
}
pub extern "C" fn print_wrapper(
args: *mut pxs_Var,
) -> *mut pxs_Var {
unsafe {
let var_ptr = pxs_Var::from_borrow(pxs_listget(args, 1));
if let Ok(msg) = var_ptr.get_string() {
println!("Lua sent: {}", msg);
}
}
pxs_Var::new_null().into_raw()
}
pub extern "C" fn add_wrapper(
args: *mut pxs_Var,
) -> *mut pxs_Var {
unsafe {
let n1 = pxs_Var::from_borrow(pxs_listget(args, 1));
let n2 = pxs_Var::from_borrow(pxs_listget(args, 2));
pxs_Var::new_i64(n1.value.i64_val + n2.value.i64_val).into_raw()
}
}
pub extern "C" fn sub_wrapper(
args: *mut pxs_Var,
) -> *mut pxs_Var {
unsafe {
let n1 = pxs_Var::from_borrow(pxs_listget(args, 1));
let n2 = pxs_Var::from_borrow(pxs_listget(args, 2));
pxs_Var::new_i64(n2.value.i64_val - n1.value.i64_val).into_raw()
}
}
unsafe extern "C" fn file_loader(file_path: *const c_char) -> *mut c_char {
let file_path = unsafe { CStr::from_ptr(file_path).to_str().unwrap() };
if file_path.is_empty() {
return create_raw_string!("");
}
let file_exists = std::fs::exists(file_path).unwrap();
if !file_exists {
return create_raw_string!("");
}
let contents = std::fs::read_to_string(file_path).unwrap();
create_raw_string!(contents)
}
unsafe extern "C" fn call_function(
args: pxs_VarT,
) -> pxs_VarT {
let func = pxs_listget(args, 1);
let argc = pxs_listlen(args);
let res = if argc > 2 {
pxs_varcall(pxs_listget(args, 0), func, pxs_newcopy(pxs_listget(args, 2)))
} else {
pxs_varcall(pxs_listget(args, 0), func, pxs_newlist())
};
res
}
fn test_add_module() {
pxs_initialize();
let module_name = create_raw_string!("pxs");
let module = pxs_newmod(module_name);
let add_name = create_raw_string!("add");
let n1_name = create_raw_string!("n1");
let n2_name: *mut i8 = create_raw_string!("n2");
pxs_addfunc(module, add_name, add_wrapper);
let n1 = pxs_newint(1);
let n2 = pxs_newint(2);
pxs_addvar(module, n1_name, n1);
pxs_addvar(module, n2_name, n2);
let name = create_raw_string!("print");
pxs_addfunc(module, name, print_wrapper);
let var_name = create_raw_string!("name");
let jordan = create_raw_string!("Jordan");
let var = pxs_newstring(jordan);
pxs_addvar(module, var_name, var);
let object_name = create_raw_string!("Person");
pxs_addobject(module, object_name, new_person);
let call_name = create_raw_string!("call_function");
pxs_addfunc(module, call_name, call_function);
free_raw_string!(call_name);
let math_module_name = create_raw_string!("math");
let math_module = pxs_newmod(math_module_name);
let sub_name = create_raw_string!("sub");
let zero_name = create_raw_string!("ZERO");
pxs_addfunc(math_module, sub_name, sub_wrapper);
pxs_addvar(math_module, zero_name, pxs_newint(0));
let diary_name = create_raw_string!("Diary");
let ddiary_name = create_raw_string!("DDiary");
pxs_addobject(math_module, diary_name, new_diary);
pxs_addfunc(math_module, sub_name, sub_wrapper);
pxs_addvar(math_module, zero_name, pxs_newint(0));
let args = pxs_newlist();
pxs_listadd(args, pxs_Var::new_string("Test".to_string()).into_raw());
pxs_addvar(math_module, ddiary_name, pxs_newfactory(new_diary, args));
pxs_add_submod(module, math_module);
pxs_addmod(module);
free_raw_string!(diary_name);
free_raw_string!(ddiary_name);
free_raw_string!(zero_name);
free_raw_string!(module_name);
free_raw_string!(add_name);
free_raw_string!(n1_name);
free_raw_string!(n2_name);
free_raw_string!(object_name);
free_raw_string!(name);
free_raw_string!(var_name);
free_raw_string!(math_module_name);
free_raw_string!(sub_name);
}
#[test]
fn test_execute() {
pxs_initialize();
test_add_module();
pxs_set_filereader(file_loader);
let lua_code = r#"
local pxs = require('pxs')
local pxs_math = require('pxs.math')
pxs.print("DDiary: " .. tostring(pxs_math.DDiary))
local ft_object = require('pad.ft_object')
ft_object.function_from_outside()
local msg = "Welcome, " .. pxs.name
pxs.print(msg)
local result = pxs.add(pxs.n1, pxs.n2)
pxs.print(tostring(pxs.n1))
pxs.print(tostring(pxs.n2))
pxs.print(tostring(result))
pxs.print("Module result: " .. tostring(result))
if result ~= 3 then
error("Math, Expected 3, got " .. tostring(result))
end
local res = pxs_math.sub(1, 2)
if res ~= 1 then
error("Math, Expected 1, got " .. tostring(res))
end
local zero = pxs_math.ZERO
if zero ~= 0 then
error("Math, Exptected 0, got " .. tostring(zero))
else
pxs.print("0 is all good my man")
end
local person = pxs.Person("Jordan")
pxs.print(person:get_name())
person:set_name("Jordan Castro")
pxs.print(person:get_name())
-- Test calling function.
function hadd(n1, n2)
return n1 + n2
end
-- Call it
pxs.print(tostring(pxs.call_function(hadd, {1,2})))
function get_pi()
return 3.145
end
pxs.print(tostring(pxs.call_function(get_pi)))
"#;
let err = LuaScripting::execute(lua_code, "<test>");
assert!(err.is_empty(), "Lua Error is not empty: {}", err);
let script = r#"
local pxs = require('pxs')
local pxs_math = require('pxs.math')
function main()
return pxs_math.sub(1,2)
end
return main()"#;
let script_raw = create_raw_string!(script);
let result = pxs_eval(script_raw, pxs_Runtime::pxs_Lua);
assert!(!result.is_null(), "Lua result is null.");
let str = pxs_tostring(pxs_newint(pxs_Runtime::pxs_Lua as i64), result);
assert!(!str.is_null(), "Str is null.");
let contents = pxs_getstring(str);
assert!(!contents.is_null(), "Contents is null.");
let owned = own_string!(contents);
println!("{owned}");
free_raw_string!(script_raw);
pxs_finalize();
}
}