use std::{
cell::Cell,
collections::HashMap,
ffi::{CStr, CString, c_char, c_void},
hash::Hash,
ptr,
};
use anyhow::{Error, anyhow};
use crate::{
borrow_string, create_raw_string,
shared::{PtrMagic, object::{apply_ref_count_alloc, apply_ref_count_delete, get_object}, pxs_Runtime},
};
macro_rules! write_func {
($ (($func_name:ident, $field_name:ident, $ret_type:ty, $tag_variant:path) ),* $(,)?) => {
$(
#[doc = concat!("Returns the ", stringify!($ret_type), " value if the tag is ", stringify!($tag_variant), ".")]
pub fn $func_name(&self) -> Result<$ret_type, Error> {
if self.tag == $tag_variant {
unsafe {
Ok(self.value.$field_name)
}
} else {
Err(anyhow!("Var is not the expected type of {:#?}. It is instead a: {:#?}", $tag_variant, self.tag))
}
}
)*
};
}
macro_rules! write_new_methods {
($($t:ty, $func:ident, $vt:expr, $vn:ident);*) => {
$(
pub fn $func(val:$t) -> Self {
Self {
tag: $vt,
value: pxs_VarValue { $vn: val },
deleter: Cell::new(default_deleter)
}
}
)*
};
}
macro_rules! write_is_methods {
($($func:ident, $vt:expr);*) => {
$(
pub fn $func(&self) -> bool {
self.tag == $vt
}
)*
};
}
#[repr(C)]
#[derive(Debug, PartialEq, Clone, Copy)]
#[allow(non_camel_case_types)]
pub enum pxs_VarType {
pxs_Int64,
pxs_UInt64,
pxs_String,
pxs_Bool,
pxs_Float64,
pxs_Null,
pxs_Object,
pxs_HostObject,
pxs_List,
pxs_Function,
pxs_Factory,
pxs_Exception,
pxs_Map,
}
#[allow(non_camel_case_types)]
pub struct pxs_VarObject {
object_val: *mut c_void,
host_ptr: i32
}
impl PtrMagic for pxs_VarObject {}
impl pxs_VarObject {
pub fn new(val: *mut c_void, host_ptr: i32) -> Self {
Self {
object_val: val,
host_ptr: host_ptr
}
}
pub fn get_raw(&self) -> *mut c_void {
self.object_val
}
pub fn new_as_host(val: *mut c_void, host_ptr: i32) -> Self {
Self::new(val, host_ptr)
}
pub fn new_lang_only(val: *mut c_void) -> Self {
Self::new(val, -1)
}
}
impl Clone for pxs_VarObject {
fn clone(&self) -> Self {
if self.host_ptr != -1 {
apply_ref_count_alloc(self.host_ptr);
}
Self {
object_val: self.object_val,
host_ptr: self.host_ptr
}
}
}
impl Drop for pxs_VarObject {
fn drop(&mut self) {
if self.host_ptr == -1 {
return;
}
apply_ref_count_delete(self.host_ptr);
}
}
#[allow(non_camel_case_types)]
pub struct pxs_VarMap {
map: HashMap<pxs_Var, pxs_Var>,
}
impl PtrMagic for pxs_VarMap {}
impl pxs_VarMap {
pub fn new() -> Self {
Self {
map: HashMap::new(),
}
}
pub fn add_item(&mut self, key: pxs_Var, value: pxs_Var) {
let _ = self.map.insert(key, value);
}
pub fn del_item(&mut self, key: &pxs_Var) {
let _ = self.map.remove(key);
}
pub fn len(&self) -> usize {
self.map.len()
}
pub fn get_item(&self, key: &pxs_Var) -> Option<&pxs_Var> {
self.map.get(key)
}
pub fn keys(&self) -> Vec<&pxs_Var> {
self.map.keys().collect()
}
}
#[allow(non_camel_case_types)]
pub struct pxs_FactoryHolder {
pub callback: super::func::pxs_Func,
pub args: *mut pxs_Var,
}
impl pxs_FactoryHolder {
pub fn get_args(&self, rt: pxs_Runtime) -> pxs_Var {
let args = self.args;
assert!(!args.is_null(), "Factory args must not be null");
unsafe {
let args_clone = pxs_Var::from_borrow(self.args).clone();
assert!(args_clone.is_list(), "Factory args must be a list");
let args_list = args_clone.get_list().unwrap();
args_list.vars.insert(0, pxs_Var::new_i64(rt.into_i64()));
args_clone
}
}
pub fn call(&self, rt: pxs_Runtime) -> pxs_Var {
let args = self.get_args(rt);
let args_raw = args.into_raw();
let res = unsafe { (self.callback)(args_raw) };
let var = if res.is_null() {
pxs_Var::new_null()
} else {
pxs_Var::from_raw(res)
};
let _ = pxs_Var::from_raw(args_raw);
var
}
}
impl PtrMagic for pxs_FactoryHolder {}
impl Drop for pxs_FactoryHolder {
fn drop(&mut self) {
if self.args.is_null() {
return;
}
let _ = pxs_Var::from_raw(self.args);
}
}
#[allow(non_camel_case_types)]
pub struct pxs_VarList {
pub vars: Vec<pxs_Var>,
}
impl PtrMagic for pxs_VarList {}
impl pxs_VarList {
pub fn new() -> Self {
pxs_VarList { vars: vec![] }
}
fn get_rindex(&self, index: i32) -> i32 {
if index < 0 {
(self.vars.len() as i32) + index
} else {
index
}
}
pub fn add_item(&mut self, item: pxs_Var) {
self.vars.push(item);
}
pub fn get_item(&self, index: i32) -> Option<&pxs_Var> {
let r_index = self.get_rindex(index);
if r_index < 0 {
None
} else {
self.vars.get(r_index as usize)
}
}
pub fn set_item(&mut self, item: pxs_Var, index: i32) -> bool {
let r_index = self.get_rindex(index);
if r_index < 0 {
return false;
}
if self.vars.len() < r_index as usize {
false
} else {
self.vars[r_index as usize] = item;
true
}
}
pub fn del_item(&mut self, index: i32) -> bool {
let r_index = self.get_rindex(index);
if r_index < 0 {
return false;
}
if self.vars.len() < r_index as usize {
false
} else {
self.vars.remove(index as usize);
true
}
}
pub fn len(&self) -> usize {
self.vars.len()
}
pub fn insert_item(&mut self, index: usize, item: pxs_Var) {
self.vars.insert(index, item);
}
}
#[repr(C)]
#[allow(non_camel_case_types)]
pub union pxs_VarValue {
pub i64_val: i64,
pub u64_val: u64,
pub string_val: *mut c_char,
pub bool_val: bool,
pub f64_val: f64,
pub null_val: *const c_void,
pub object_val: *mut pxs_VarObject,
pub host_object_val: i32,
pub list_val: *mut pxs_VarList,
pub function_val: *mut c_void,
pub factory_val: *mut pxs_FactoryHolder,
pub map_val: *mut pxs_VarMap,
}
#[allow(non_camel_case_types)]
pub type pxs_DeleterFn = unsafe extern "C" fn(*mut c_void);
pub unsafe extern "C" fn default_deleter(_ptr: *mut c_void) {
}
#[repr(C)]
#[allow(non_camel_case_types)]
pub struct pxs_Var {
pub tag: pxs_VarType,
pub value: pxs_VarValue,
pub deleter: Cell<pxs_DeleterFn>,
}
impl pxs_Var {
pub unsafe fn slice_raw(argv: *mut *mut Self, argc: usize) -> &'static [*mut pxs_Var] {
unsafe { std::slice::from_raw_parts(argv, argc) }
}
pub fn get_host_ptr(&self) -> *mut c_void {
let object = get_object(self.get_host_idx());
if let Some(obj) = object {
obj.ptr
} else {
std::ptr::null_mut()
}
}
pub fn get_string(&self) -> Result<String, Error> {
if self.tag == pxs_VarType::pxs_String || self.tag == pxs_VarType::pxs_Exception {
unsafe {
if self.value.string_val.is_null() {
return Err(anyhow!("String pointer is null"));
}
let c_str = CStr::from_ptr(self.value.string_val);
let res = c_str.to_str();
if res.is_err() {
return Err(anyhow!(res.err().unwrap()));
}
Ok(res.unwrap().to_string())
}
} else {
Err(anyhow!("Var is not a string."))
}
}
pub fn new_string(val: String) -> Self {
let cstr = CString::new(val).expect("Could not create CString.");
pxs_Var {
tag: pxs_VarType::pxs_String,
value: pxs_VarValue {
string_val: cstr.into_raw(),
},
deleter: Cell::new(default_deleter),
}
}
pub fn new_null() -> Self {
pxs_Var {
tag: pxs_VarType::pxs_Null,
value: pxs_VarValue {
null_val: ptr::null(),
},
deleter: Cell::new(default_deleter),
}
}
pub fn new_host_object(ptr: i32) -> Self {
pxs_Var {
tag: pxs_VarType::pxs_HostObject,
value: pxs_VarValue {
host_object_val: ptr,
},
deleter: Cell::new(default_deleter),
}
}
pub fn new_object(ptr: pxs_VarObject, deleter: Option<pxs_DeleterFn>) -> Self {
let deleter = if let Some(d) = deleter {
d
} else {
default_deleter
};
pxs_Var {
tag: pxs_VarType::pxs_Object,
value: pxs_VarValue { object_val: ptr.into_raw() },
deleter: Cell::new(deleter),
}
}
pub fn new_list() -> Self {
pxs_Var {
tag: pxs_VarType::pxs_List,
value: pxs_VarValue {
list_val: pxs_VarList::new().into_raw(),
},
deleter: Cell::new(default_deleter),
}
}
pub fn new_list_with(vars: Vec<pxs_Var>) -> Self {
let mut list = pxs_VarList::new();
list.vars = vars;
pxs_Var {
tag: pxs_VarType::pxs_List,
value: pxs_VarValue {
list_val: list.into_raw(),
},
deleter: Cell::new(default_deleter),
}
}
pub fn new_function(ptr: *mut c_void, deleter: Option<pxs_DeleterFn>) -> Self {
let deleter = if let Some(d) = deleter {
d
} else {
default_deleter
};
pxs_Var {
tag: pxs_VarType::pxs_Function,
value: pxs_VarValue { function_val: ptr },
deleter: Cell::new(deleter),
}
}
pub fn new_factory(func: super::func::pxs_Func, args: pxs_VarT) -> Self {
let factory = pxs_FactoryHolder {
callback: func,
args,
};
pxs_Var {
tag: pxs_VarType::pxs_Factory,
value: pxs_VarValue {
factory_val: factory.into_raw(),
},
deleter: Cell::new(default_deleter),
}
}
pub fn new_exception<T: ToString>(msg: T) -> Self {
pxs_Var {
tag: pxs_VarType::pxs_Exception,
value: pxs_VarValue {
string_val: create_raw_string!(msg.to_string()),
},
deleter: Cell::new(default_deleter),
}
}
pub fn new_map() -> Self {
pxs_Var {
tag: pxs_VarType::pxs_Map,
value: pxs_VarValue {
map_val: pxs_VarMap::new().into_raw(),
},
deleter: Cell::new(default_deleter),
}
}
pub fn get_host_idx(&self) -> i32 {
match self.tag {
pxs_VarType::pxs_Int64 => self.get_i64().unwrap() as i32,
pxs_VarType::pxs_UInt64 => self.get_u64().unwrap() as i32,
pxs_VarType::pxs_HostObject => unsafe { self.value.host_object_val },
_ => -1,
}
}
pub fn get_object_ptr(&self) -> *mut c_void {
match self.tag {
pxs_VarType::pxs_Object => unsafe {
let object = pxs_VarObject::from_borrow(self.value.object_val);
object.get_raw()
},
_ => std::ptr::null_mut(),
}
}
pub fn get_list(&self) -> Option<&mut pxs_VarList> {
if !self.is_list() {
None
} else {
unsafe { Some(pxs_VarList::from_borrow(self.value.list_val)) }
}
}
pub fn get_factory(&self) -> Option<&mut pxs_FactoryHolder> {
if !self.is_factory() {
None
} else {
unsafe {
if self.value.factory_val.is_null() {
None
} else {
Some(pxs_FactoryHolder::from_borrow(self.value.factory_val))
}
}
}
}
pub fn get_map(&self) -> Option<&mut pxs_VarMap> {
if !self.is_map() {
None
} else {
unsafe { Some(pxs_VarMap::from_borrow(self.value.map_val)) }
}
}
unsafe fn dbg(&self) -> String {
unsafe {
let details = match self.tag {
pxs_VarType::pxs_Int64 => self.value.i64_val.to_string(),
pxs_VarType::pxs_UInt64 => self.value.u64_val.to_string(),
pxs_VarType::pxs_String => borrow_string!(self.value.string_val).to_string(),
pxs_VarType::pxs_Bool => self.value.bool_val.to_string(),
pxs_VarType::pxs_Float64 => self.value.f64_val.to_string(),
pxs_VarType::pxs_Null => "Null".to_string(),
pxs_VarType::pxs_Object => "Object".to_string(),
pxs_VarType::pxs_HostObject => {
let idx = self.get_host_idx();
let object = get_object(idx).unwrap();
object.type_name.to_string()
}
pxs_VarType::pxs_List => {
let list = self.get_list().unwrap();
let t: String = list.vars.iter().map(|v| format!("{},", v.dbg())).collect();
format!("[{t}]")
}
pxs_VarType::pxs_Function => "Function".to_string(),
pxs_VarType::pxs_Factory => "Factory".to_string(),
pxs_VarType::pxs_Exception => borrow_string!(self.value.string_val).to_string(),
pxs_VarType::pxs_Map => {
let map = self.get_map().unwrap();
let keys = map.keys();
let mut res = String::from("{");
for k in keys {
let value = map.get_item(k);
res.push_str(format!("{:#?}: {:#?},\n", k, value).as_str());
}
res.push_str("}");
res
}
};
format!("{details} :: {:p}", self)
}
}
write_func!(
(get_i64, i64_val, i64, pxs_VarType::pxs_Int64),
(get_u64, u64_val, u64, pxs_VarType::pxs_UInt64),
(get_bool, bool_val, bool, pxs_VarType::pxs_Bool),
(get_f64, f64_val, f64, pxs_VarType::pxs_Float64),
(
get_function,
function_val,
*mut c_void,
pxs_VarType::pxs_Function
)
);
write_new_methods! {
i64, new_i64, pxs_VarType::pxs_Int64, i64_val;
u64, new_u64, pxs_VarType::pxs_UInt64, u64_val;
f64, new_f64, pxs_VarType::pxs_Float64, f64_val;
bool, new_bool, pxs_VarType::pxs_Bool, bool_val
}
write_is_methods! {
is_i64, pxs_VarType::pxs_Int64;
is_u64, pxs_VarType::pxs_UInt64;
is_f64, pxs_VarType::pxs_Float64;
is_bool, pxs_VarType::pxs_Bool;
is_string, pxs_VarType::pxs_String;
is_null, pxs_VarType::pxs_Null;
is_object, pxs_VarType::pxs_Object;
is_host_object, pxs_VarType::pxs_HostObject;
is_list, pxs_VarType::pxs_List;
is_function, pxs_VarType::pxs_Function;
is_factory, pxs_VarType::pxs_Factory;
is_exception, pxs_VarType::pxs_Exception;
is_map, pxs_VarType::pxs_Map
}
pub fn shallow_copy(&self) -> pxs_Var {
unsafe{
match self.tag {
pxs_VarType::pxs_Int64 => self.clone(),
pxs_VarType::pxs_UInt64 => self.clone(),
pxs_VarType::pxs_String => self.clone(),
pxs_VarType::pxs_Bool => self.clone(),
pxs_VarType::pxs_Float64 => self.clone(),
pxs_VarType::pxs_Null => self.clone(),
pxs_VarType::pxs_Exception => self.clone(),
pxs_VarType::pxs_HostObject => self.clone(),
pxs_VarType::pxs_Object => {
let object = pxs_VarObject::from_borrow(self.value.object_val);
pxs_Var {
tag: pxs_VarType::pxs_Object,
value: pxs_VarValue {
object_val: object.clone().into_raw()
},
deleter: Cell::new(default_deleter)
}
},
pxs_VarType::pxs_List => {
let mut list = pxs_VarList::new();
let og_list_val = pxs_VarList::from_borrow(self.value.list_val);
for item in og_list_val.vars.iter() {
list.add_item(item.shallow_copy());
}
pxs_Var {
tag: pxs_VarType::pxs_List,
value: pxs_VarValue {
list_val: list.into_raw()
},
deleter: Cell::new(default_deleter)
}
},
pxs_VarType::pxs_Function => {
pxs_Var {
tag: pxs_VarType::pxs_Function,
value: pxs_VarValue {
function_val: self.value.function_val
},
deleter: Cell::new(default_deleter)
}
},
pxs_VarType::pxs_Factory => {
let og = pxs_FactoryHolder::from_borrow(self.value.factory_val);
if og.args.is_null() {
return pxs_Var::new_null();
}
let new_args = pxs_Var::new_list();
let old_args = pxs_Var::from_borrow(og.args);
if !old_args.is_list() {
return pxs_Var::new_null();
}
let old_list = old_args.get_list().unwrap();
let new_list = new_args.get_list().unwrap();
for var in old_list.vars.iter() {
new_list.add_item(var.shallow_copy());
}
let f = pxs_FactoryHolder {
args: new_args.into_raw(),
callback: og.callback,
};
pxs_Var {
tag: pxs_VarType::pxs_Factory,
value: pxs_VarValue {
factory_val: f.into_raw(),
},
deleter: Cell::new(default_deleter),
}
},
pxs_VarType::pxs_Map => {
let mut map = pxs_VarMap::new();
let og_map = self.get_map().unwrap();
let keys = og_map.keys();
for k in keys {
let v = og_map.get_item(k);
if let Some(v) = v {
map.add_item(k.shallow_copy(), v.shallow_copy());
}
}
pxs_Var {
tag: pxs_VarType::pxs_Map,
value: pxs_VarValue {
map_val: map.into_raw()
},
deleter: Cell::new(default_deleter)
}
},
}
}
}
}
unsafe impl Send for pxs_Var {}
unsafe impl Sync for pxs_Var {}
impl Drop for pxs_Var {
fn drop(&mut self) {
if self.tag == pxs_VarType::pxs_String || self.tag == pxs_VarType::pxs_Exception {
unsafe {
if !self.value.string_val.is_null() {
let _ = CString::from_raw(self.value.string_val);
self.value.string_val = ptr::null_mut();
}
}
} else if self.tag == pxs_VarType::pxs_List {
let _ = unsafe {
pxs_VarList::from_raw(self.value.list_val)
};
} else if self.tag == pxs_VarType::pxs_Object {
unsafe {
if self.value.object_val.is_null() {
return;
}
let object = pxs_VarObject::from_raw(self.value.object_val);
(self.deleter.get())(object.get_raw());
};
} else if self.tag == pxs_VarType::pxs_Function {
unsafe {
if self.value.object_val.is_null() {
return;
}
(self.deleter.get())(self.value.function_val)
};
} else if self.tag == pxs_VarType::pxs_Factory {
unsafe {
if self.value.factory_val.is_null() {
return;
}
let _ = pxs_FactoryHolder::from_raw(self.value.factory_val);
}
} else if self.tag == pxs_VarType::pxs_Map {
let _ = unsafe {
pxs_VarMap::from_raw(self.value.map_val)
};
}
}
}
impl PtrMagic for pxs_Var {}
impl Clone for pxs_Var {
fn clone(&self) -> Self {
unsafe {
match self.tag {
pxs_VarType::pxs_Int64 => pxs_Var::new_i64(self.value.i64_val),
pxs_VarType::pxs_UInt64 => pxs_Var::new_u64(self.value.u64_val),
pxs_VarType::pxs_String => {
let string = borrow_string!(self.value.string_val);
let cloned_string = string.to_string().clone();
let new_string = create_raw_string!(cloned_string);
pxs_Var {
tag: pxs_VarType::pxs_String,
value: pxs_VarValue {
string_val: new_string,
},
deleter: Cell::new(default_deleter),
}
}
pxs_VarType::pxs_Bool => pxs_Var::new_bool(self.value.bool_val),
pxs_VarType::pxs_Float64 => pxs_Var::new_f64(self.value.f64_val),
pxs_VarType::pxs_Null => pxs_Var::new_null(),
pxs_VarType::pxs_Object => {
let object = pxs_VarObject::from_borrow(self.value.object_val);
let r = pxs_Var {
tag: pxs_VarType::pxs_Object,
value: pxs_VarValue {
object_val: object.clone().into_raw(),
},
deleter: Cell::new(self.deleter.get()),
};
self.deleter.set(default_deleter);
r
}
pxs_VarType::pxs_HostObject => pxs_Var::new_host_object(self.value.host_object_val),
pxs_VarType::pxs_List => {
let mut list = pxs_VarList::new();
let og_list_val = pxs_VarList::from_borrow(self.value.list_val);
for item in og_list_val.vars.iter() {
list.add_item(item.clone());
}
pxs_Var {
tag: pxs_VarType::pxs_List,
value: pxs_VarValue {
list_val: list.into_raw(),
},
deleter: Cell::new(default_deleter),
}
}
pxs_VarType::pxs_Function => {
let r = pxs_Var {
tag: pxs_VarType::pxs_Function,
value: pxs_VarValue {
function_val: self.value.function_val,
},
deleter: Cell::new(self.deleter.get()),
};
self.deleter.set(default_deleter);
r
}
pxs_VarType::pxs_Factory => {
let og = pxs_FactoryHolder::from_borrow(self.value.factory_val);
if og.args.is_null() {
return pxs_Var::new_null();
}
let new_args = pxs_Var::new_list();
let old_args = pxs_Var::from_borrow(og.args);
if !old_args.is_list() {
return pxs_Var::new_null();
}
let old_list = old_args.get_list().unwrap();
let new_list = new_args.get_list().unwrap();
for var in old_list.vars.iter() {
new_list.add_item(var.clone());
}
let f = pxs_FactoryHolder {
args: new_args.into_raw(),
callback: og.callback,
};
pxs_Var {
tag: pxs_VarType::pxs_Factory,
value: pxs_VarValue {
factory_val: f.into_raw(),
},
deleter: Cell::new(default_deleter),
}
}
pxs_VarType::pxs_Exception => {
let string = borrow_string!(self.value.string_val);
let cloned_string = string.to_string().clone();
let new_string = create_raw_string!(cloned_string);
pxs_Var {
tag: pxs_VarType::pxs_Exception,
value: pxs_VarValue {
string_val: new_string,
},
deleter: Cell::new(default_deleter),
}
}
pxs_VarType::pxs_Map => {
let mut map = pxs_VarMap::new();
let og_map = self.get_map().unwrap();
let keys = og_map.keys();
for k in keys {
let v = og_map.get_item(k);
if let Some(v) = v {
map.add_item(k.clone(), v.clone());
}
}
pxs_Var {
tag: pxs_VarType::pxs_Map,
value: pxs_VarValue {
map_val: map.into_raw()
},
deleter: Cell::new(default_deleter)
}
}
}
}
}
}
impl std::fmt::Debug for pxs_Var {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let debug_val: &dyn std::fmt::Debug = unsafe { &self.dbg() };
f.debug_struct("pxs_Var")
.field("tag", &self.tag)
.field("value", debug_val)
.finish()
}
}
impl PartialEq for pxs_Var {
fn eq(&self, other: &Self) -> bool {
unsafe {
match (&self.tag, &other.tag) {
(pxs_VarType::pxs_Int64, pxs_VarType::pxs_Int64) => {
self.value.i64_val == other.value.i64_val
}
(pxs_VarType::pxs_Int64, _) => false,
(pxs_VarType::pxs_UInt64, pxs_VarType::pxs_UInt64) => {
self.value.u64_val == other.value.u64_val
}
(pxs_VarType::pxs_UInt64, _) => false,
(pxs_VarType::pxs_String, pxs_VarType::pxs_String) => {
self.get_string().unwrap_or(String::new())
== other.get_string().unwrap_or(String::new())
}
(pxs_VarType::pxs_String, _) => false,
(pxs_VarType::pxs_Bool, pxs_VarType::pxs_Bool) => {
self.value.bool_val == other.value.bool_val
}
(pxs_VarType::pxs_Bool, _) => false,
(pxs_VarType::pxs_Float64, pxs_VarType::pxs_Float64) => {
self.value.f64_val == other.value.f64_val
}
(pxs_VarType::pxs_Float64, _) => false,
(pxs_VarType::pxs_Null, _) => false,
(pxs_VarType::pxs_Object, _) => false,
(pxs_VarType::pxs_HostObject, _) => false,
(pxs_VarType::pxs_List, _) => false,
(pxs_VarType::pxs_Function, _) => false,
(pxs_VarType::pxs_Factory, _) => false,
(pxs_VarType::pxs_Exception, _) => false,
(pxs_VarType::pxs_Map, _) => false,
}
}
}
}
impl Eq for pxs_Var {}
impl Hash for pxs_Var {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
unsafe {
match self.tag {
pxs_VarType::pxs_Int64 => self.value.i64_val.hash(state),
pxs_VarType::pxs_UInt64 => self.value.u64_val.hash(state),
pxs_VarType::pxs_String => self.get_string().unwrap_or(String::new()).hash(state),
pxs_VarType::pxs_Bool => self.value.bool_val.hash(state),
pxs_VarType::pxs_Float64 => self.value.f64_val.to_bits().hash(state),
_ => panic!("Can not Hash none basic pxs_VarType")
}
}
}
}
impl pxs_Var {
pub fn incorrect_type_ep(expected: pxs_VarType, found: pxs_VarType) -> Self {
Self::new_exception(format!("Expected {:#?}, found {:#?}", expected, found))
}
pub fn incorrect_types_ep(allowed: Vec<pxs_VarType>, found: pxs_VarType) -> Self {
Self::new_exception(format!("Allowed types: {:#?}, found: {:#?}", allowed, found))
}
pub fn null_params_ep() -> Self {
Self::new_exception("Paramaters are null")
}
pub fn null_param_ep<T: ToString>(name:T) -> Self {
Self::new_exception(format!("{} is null", name.to_string()))
}
pub fn unkown_runtime_ep(runtime: i64) -> Self {
Self::new_exception(format!("Unkown runtime: {runtime}"))
}
pub fn unkown_runtime_var_ep(runtime: pxs_VarT) -> Self {
let var = unsafe{Self::from_borrow(runtime)};
Self::new_exception(format!("Unkown runtime: {:#?}", var))
}
pub fn item_not_found_ep() -> Self {
Self::new_exception("Item not found")
}
pub fn feature_not_enabled_ep(feature: &str) -> Self {
Self::new_exception(format!("{feature} is not enabled."))
}
}
pub trait ObjectMethods {
fn object_call(var: &pxs_Var, method: &str, args: &mut pxs_VarList) -> Result<pxs_Var, Error>;
fn call_method(method: &str, args: &mut pxs_VarList) -> Result<pxs_Var, Error>;
fn var_call(method: &pxs_Var, args: &mut pxs_VarList) -> Result<pxs_Var, Error>;
fn get(var: &pxs_Var, key: &str) -> Result<pxs_Var, Error>;
fn set(var: &pxs_Var, key: &str, value: &pxs_Var) -> Result<pxs_Var, Error>;
fn get_from_name(name: &str) -> Result<pxs_Var, Error>;
}
#[allow(non_camel_case_types)]
pub type pxs_VarT = *mut pxs_Var;