Skip to main content

pixelscript/shared/
var.rs

1// Copyright 2026 Jordan Castro <jordan@grupojvm.com>
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
4//
5// http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
8//
9use std::{
10    cell::Cell,
11    collections::HashMap,
12    ffi::{CStr, CString, c_char, c_void},
13    hash::Hash,
14    ptr,
15};
16
17use anyhow::{Error, anyhow};
18
19use crate::{
20    borrow_string, borrow_var, create_raw_string, shared::{PtrMagic, get_current_arena_id, object::{apply_ref_count_alloc, apply_ref_count_delete, get_object}, pxs_Runtime, remove_var_from_arena, save_var_in_arena}
21};
22
23/// Macro for writing out the Var:: get methods.
24macro_rules! write_func {
25    ($ (($func_name:ident, $field_name:ident, $ret_type:ty, $tag_variant:path) ),* $(,)?) => {
26        $(
27            #[doc = concat!("Returns the ", stringify!($ret_type), " value if the tag is ", stringify!($tag_variant), ".")]
28            pub fn $func_name(&self) -> Result<$ret_type, Error> {
29                if self.tag == $tag_variant {
30                    unsafe {
31                        Ok(self.value.$field_name)
32                    }
33                } else {
34                    Err(anyhow!("Var is not the expected type of {:#?}. It is instead a: {:#?}", $tag_variant, self.tag))
35                }
36            }
37        )*
38    };
39}
40
41/// Macro for writing out the new_t methods in Var
42macro_rules! write_new_methods {
43    ($($t:ty, $func:ident, $vt:expr, $vn:ident);*) => {
44        $(
45            pub fn $func(val:$t) -> Self {
46                Self::new(
47                    $vt,
48                    pxs_VarValue { $vn: val },
49                    default_deleter
50                )
51            }
52        )*
53    };
54}
55
56/// Macro for writing out the is_t methods in Var
57macro_rules! write_is_methods {
58    ($($func:ident, $vt:expr);*) => {
59        $(
60            pub fn $func(&self) -> bool {
61                self.tag == $vt
62            }
63        )*
64    };
65}
66
67// // Macro for writing out the FromVars
68// macro_rules! implement_from_var {
69//     ($($t:ty, $func:ident);*) => {
70//         $(
71//             impl FromVar for $t {
72//                 fn from_var(var:&Var) -> Result<Self, Error> {
73//                     var.$func()
74//                 }
75//             }
76//         )*
77//     };
78// }
79
80/// This represents the variable type that is being read or created.
81#[repr(C)]
82#[derive(Debug, PartialEq, Clone, Copy)]
83#[allow(non_camel_case_types)]
84pub enum pxs_VarType {
85    pxs_Int64,
86    pxs_UInt64,
87    pxs_String,
88    pxs_Bool,
89    pxs_Float64,
90    /// Lua (nil), Python (None), JS/easyjs (null/undefined)
91    pxs_Null,
92    /// Lua (Tree), Python (Class), JS/easyjs (Prototype)
93    pxs_Object,
94    /// Host object converted when created.
95    /// Lua (Tree), Python (object), JS/easyjs (Prototype think '{}')
96    pxs_HostObject,
97    /// Lua (Tree), Python (list), JS/easyjs (Array)
98    pxs_List,
99    /// Lua (Value), Python (def or lambda), JS/easyjs (anon function)
100    pxs_Function,
101    /// Internal object only. It will get converted into the result before hitting the runtime
102    pxs_Factory,
103    /// Exception is any exception happening at the language level. Pixel Script errors will be caught with pxs_Error in a future release
104    pxs_Exception,
105    /// A Map Type that ONLY goes from PixelScript to scripting language. You will NEVER receive a Map from a scripting language. It will
106    /// always default to `pxs_Object`. Does not support all `pxs_VarType`s.
107    pxs_Map,
108}
109
110/// A `Object` in pixelscript is wrapped with a potential host_ptr. This allows for non language specific ref counting.
111/// 
112/// To access the raw pointer, use `get_raw()`. Reference counting is automatically applied when this struct is dropped.
113#[allow(non_camel_case_types)]
114pub struct pxs_VarObject {
115    object_val: *mut c_void,
116    host_ptr: i32
117}
118
119impl PtrMagic for pxs_VarObject {}
120
121impl pxs_VarObject {
122    pub fn new(val: *mut c_void, host_ptr: i32) -> Self {
123        Self {
124            object_val: val,
125            host_ptr: host_ptr
126        }
127    }
128
129    /// Get the raw object pointer.
130    pub fn get_raw(&self) -> *mut c_void {
131        self.object_val
132    }
133
134    /// New HostObject Object
135    pub fn new_as_host(val: *mut c_void, host_ptr: i32) -> Self {
136        Self::new(val, host_ptr)
137    }
138
139    /// New Non host object.
140    pub fn new_lang_only(val: *mut c_void) -> Self {
141        Self::new(val, -1)
142    }
143}
144
145impl Clone for pxs_VarObject {
146    fn clone(&self) -> Self {
147        // Do ref counting
148        if self.host_ptr != -1 {
149            apply_ref_count_alloc(self.host_ptr);
150        }
151
152        Self {
153            object_val: self.object_val,
154            host_ptr: self.host_ptr
155        }
156    }
157}
158
159impl Drop for pxs_VarObject {
160    fn drop(&mut self) {
161        if self.host_ptr == -1 {
162            return;
163        }
164
165        // Ref counting
166        apply_ref_count_delete(self.host_ptr);
167    }
168}
169
170/// A `Map` in pixelscript is very simply a Key (pxs_Var) to Value (pxs_Var) pair.
171/// 
172/// In Python it's a dictionary, in Lua it's a table, and in JS it's a object.
173#[allow(non_camel_case_types)]
174pub struct pxs_VarMap {
175    /// Key of pxs_Var => value of pxs_Var.
176    map: HashMap<pxs_Var, pxs_Var>,
177}
178
179impl PtrMagic for pxs_VarMap {}
180
181impl pxs_VarMap {
182    /// A new map
183    pub fn new() -> Self {
184        Self {
185            map: HashMap::new(),
186        }
187    }
188
189    /// Add a new item.
190    ///
191    /// Old value (if any) gets dropped.
192    pub fn add_item(&mut self, mut key: pxs_Var, mut value: pxs_Var) {
193        key.remove_from_arena();
194        value.remove_from_arena();
195        // Drop old value.
196        let _ = self.map.insert(key, value);
197    }
198
199    /// Remove a item by key.
200    /// 
201    /// Old value gets dropped.
202    pub fn del_item(&mut self, key: &pxs_Var) {
203        let _ = self.map.remove(key);
204    }
205
206    /// Current length of map
207    pub fn len(&self) -> usize {
208        self.map.len()
209    }
210
211    /// Get value from key.
212    pub fn get_item(&self, key: &pxs_Var) -> Option<&pxs_Var> {
213        self.map.get(key)
214    }
215
216    /// Get keys
217    pub fn keys(&self) -> Vec<&pxs_Var> {
218        self.map.keys().collect()
219    }
220}
221
222/// A Factory variable data holder.
223///
224/// Holds a callback for creation. And the arguments to be supplied.
225/// Runtime will be supplied automatically.
226#[allow(non_camel_case_types)]
227pub struct pxs_FactoryHolder {
228    pub callback: super::func::pxs_Func,
229    pub args: *mut pxs_Var,
230}
231
232impl pxs_FactoryHolder {
233    /// Get a cloned list of args. This list will include the runtime passed as the
234    /// first item. Returns a owned pxs_Var not a pointer.
235    pub fn get_args(&self, rt: pxs_Runtime) -> pxs_Var {
236        let args = self.args;
237        // Check null
238        assert!(!args.is_null(), "Factory args must not be null");
239        unsafe {
240            // Clone
241            let args_clone = pxs_Var::from_borrow(self.args).clone();
242            // Check list
243            assert!(args_clone.is_list(), "Factory args must be a list");
244            // Get list and add runtime
245            let args_list = args_clone.get_list().unwrap();
246            args_list.vars.insert(0, pxs_Var::new_i64(rt.into_i64()));
247
248            args_clone
249        }
250    }
251
252    /// Call the FactoryHolder function with the args!
253    pub fn call(&self, rt: pxs_Runtime) -> pxs_Var {
254        let args = self.get_args(rt);
255        // Create raw memory that lasts for the direction of this call.
256        let args_raw = args.into_raw();
257
258        let res = unsafe { (self.callback)(args_raw) };
259        let var = if res.is_null() {
260            pxs_Var::new_null()
261        } else {
262            pxs_Var::from_raw(res)
263        };
264        // Drop raw args memory
265        let _ = pxs_Var::from_raw(args_raw);
266
267        // Return the variable result
268        var
269    }
270}
271
272impl PtrMagic for pxs_FactoryHolder {
273    fn into_raw(self) -> *mut Self {
274        // Remove args and all args internal from arena
275        let args = unsafe{pxs_Var::from_borrow(self.args)};
276        let list = args.get_list().unwrap();
277        for v in list.vars.iter_mut() {
278            v.remove_from_arena();
279        }
280        args.remove_from_arena();
281        Box::into_raw(Box::new(self))
282    }
283}
284
285impl Drop for pxs_FactoryHolder {
286    fn drop(&mut self) {
287        if self.args.is_null() {
288            return;
289        }
290
291        // Drop args
292        let _ = pxs_Var::from_raw(self.args);
293    }
294}
295
296/// Holds data for a pxs_Var of list.
297///
298/// It holds multiple pxsVar within.
299///
300/// When creating call:
301///
302/// `pixelscript_var_newlist()`.
303///
304/// To add items
305///
306/// `pixelscript_var_list_add(list_ptr, item_ptr)`
307///
308/// To get items
309///
310/// `pixelscript_var_list_get(list_ptr, index)`
311///
312/// A full example looks like:
313/// ```c
314/// // Create a new list (you never interact with pxs_VarList directly...)
315/// pxs_Var* list = pixelscript_var_newlist();
316///
317/// // Add a item
318/// pxs_Var* number = pixelscript_var_newint(1);
319/// pixelscript_var_list_add(list, number);
320///
321/// // Get a item
322/// pxs_Var* item_got = pixelscript_var_list_get(list, 0);
323/// ```
324#[allow(non_camel_case_types)]
325pub struct pxs_VarList {
326    pub vars: Vec<pxs_Var>,
327}
328
329impl PtrMagic for pxs_VarList {
330    fn into_raw(mut self) -> *mut Self {
331        // Remove all internal vars from arena
332        for v in self.vars.iter_mut() {
333            v.remove_from_arena();
334        }
335        Box::into_raw(Box::new(self))
336    }
337}
338
339impl pxs_VarList {
340    /// Create a new VarList
341    pub fn new() -> Self {
342        pxs_VarList { vars: vec![] }
343    }
344
345    fn get_rindex(&self, index: i32) -> i32 {
346        if index < 0 {
347            (self.vars.len() as i32) + index
348        } else {
349            index
350        }
351    }
352
353    /// Add a Var to the list. List will take ownership.
354    pub fn add_item(&mut self, mut item: pxs_Var) {
355        item.remove_from_arena();
356        self.vars.push(item);
357    }
358
359    /// Get a Var from the list. Supports negative based indexes.
360    pub fn get_item(&self, index: i32) -> Option<&pxs_Var> {
361        // Get correct negative index.
362        let r_index = self.get_rindex(index);
363
364        if r_index < 0 {
365            None
366        } else {
367            self.vars.get(r_index as usize)
368        }
369    }
370
371    /// Set at a specific index a item.
372    ///
373    /// Index must already be filled.
374    pub fn set_item(&mut self, mut item: pxs_Var, index: i32) -> bool {
375        item.remove_from_arena();
376        // Get correct negative index.
377        let r_index = self.get_rindex(index);
378
379        if r_index < 0 {
380            return false;
381        }
382
383        if self.vars.len() < r_index as usize {
384            false
385        } else {
386            self.vars[r_index as usize] = item;
387            true
388        }
389    }
390
391    /// Remove a item at a specific index.
392    pub fn del_item(&mut self, index: i32) -> bool {
393        let r_index = self.get_rindex(index);
394
395        if r_index < 0 {
396            return false;
397        }
398
399        if self.vars.len() < r_index as usize {
400            false
401        } else {
402            self.vars.remove(index as usize);
403            true
404        }
405    }
406
407    /// Get length
408    pub fn len(&self) -> usize {
409        self.vars.len()
410    }
411
412    /// Insert a item moving all the rest to the right.
413    pub fn insert_item(&mut self, index: usize, item: pxs_Var) {
414        self.vars.insert(index, item);
415    }
416}
417
418/// The Variables actual value union.
419#[repr(C)]
420#[allow(non_camel_case_types)]
421pub union pxs_VarValue {
422    pub i64_val: i64,
423    pub u64_val: u64,
424    pub string_val: *mut c_char,
425    pub bool_val: bool,
426    pub f64_val: f64,
427    pub null_val: *const c_void,
428    pub object_val: *mut pxs_VarObject,
429    pub host_object_val: i32,
430    pub list_val: *mut pxs_VarList,
431    pub function_val: *mut c_void,
432    pub factory_val: *mut pxs_FactoryHolder,
433    pub map_val: *mut pxs_VarMap,
434}
435
436#[allow(non_camel_case_types)]
437/// Deleter Function type. It takes a *void, and returns void.
438pub type pxs_DeleterFn = unsafe extern "C" fn(*mut c_void);
439
440/// Default Var deleter fn.
441/// Use it when you don't want to delete memory.
442pub unsafe extern "C" fn default_deleter(_ptr: *mut c_void) {
443    // Empty OP
444}
445
446/// A PixelScript Var(iable).
447///
448/// This is the universal truth between all languages PixelScript supports.
449///
450/// Currently supports:
451/// - int (i32, i64, u32, u64)
452/// - float (f32, f64)
453/// - string
454/// - boolean
455/// - Objects
456/// - HostObjects (C structs acting as pseudo-classes) This in the Host can also be a Int or Uint.
457/// - List
458/// - Functions (First class functions)
459///
460/// When working with objects you must use the C-api:
461/// ```c
462/// // Calls a method on a object.
463/// pixelscript_object_call(var)
464/// ```
465///
466/// When using within a callback, if said callback was attached to a Class, the first *mut Var will be the class/object.
467///
468/// When using ints or floats, if (i32, u32, u64, f32) there is no gurantee that the supported language uses
469/// those types. Usually it defaults to i64 and f64.
470///
471/// When creating a object, this is a bit tricky but essentially you have to first create a pointer via the pixel script runtime.
472#[repr(C)]
473#[allow(non_camel_case_types)]
474pub struct pxs_Var {
475    /// A tag for the variable type.
476    pub tag: pxs_VarType,
477    /// A value as a union.
478    pub value: pxs_VarValue,
479
480    /// Optional delete method. This is used for Pointers in Objects, and Functions.
481    pub deleter: Cell<pxs_DeleterFn>,
482
483    /// IDX assigned within arena
484    pub idx: i32,
485
486    /// Arena that this variable is attached to.
487    /// This should not be manipulated via the Host.
488    pub arena: i32
489}
490
491// Rust specific functions
492impl pxs_Var {
493    pub fn new(tag: pxs_VarType, value: pxs_VarValue, deleter: pxs_DeleterFn) -> Self {
494        Self {
495            tag,
496            value,
497            deleter: Cell::new(deleter),
498            idx: -1,
499            arena: -1
500        }
501    }
502
503    pub unsafe fn slice_raw(argv: *mut *mut Self, argc: usize) -> &'static [*mut pxs_Var] {
504        unsafe { std::slice::from_raw_parts(argv, argc) }
505    }
506
507    /// Get the direct host pointer. (Not the idx) OR null if not found!
508    pub fn get_host_ptr(&self) -> *mut c_void {
509        let object = get_object(self.get_host_idx());
510        if let Some(obj) = object {
511            obj.ptr
512        } else {
513            std::ptr::null_mut()
514        }
515    }
516
517    /// Get the Rust string from the Var.
518    ///
519    /// Works for pxs_String and pxs_Exception
520    pub fn get_string(&self) -> Result<String, Error> {
521        if self.tag == pxs_VarType::pxs_String || self.tag == pxs_VarType::pxs_Exception {
522            unsafe {
523                if self.value.string_val.is_null() {
524                    return Err(anyhow!("String pointer is null"));
525                }
526
527                let c_str = CStr::from_ptr(self.value.string_val);
528                let res = c_str.to_str();
529                if res.is_err() {
530                    return Err(anyhow!(res.err().unwrap()));
531                }
532
533                Ok(res.unwrap().to_string())
534            }
535        } else {
536            Err(anyhow!("Var is not a string."))
537        }
538    }
539
540    /// Create a new String var.
541    ///
542    /// The memory is leaked and needs to be freed eventually. It is freed by Var::free_var(). And done so automatically
543    /// by the library.
544    pub fn new_string(val: String) -> Self {
545        let cstr = CString::new(val).expect("Could not create CString.");
546
547        Self::new(pxs_VarType::pxs_String, pxs_VarValue{string_val: cstr.into_raw()}, default_deleter)
548    }
549
550    /// Creates a new Null var.
551    ///
552    /// No need to free, or any of that. It cretes a *const c_void
553    pub fn new_null() -> Self {
554        Self::new(pxs_VarType::pxs_Null, pxs_VarValue{null_val: ptr::null()}, default_deleter)
555    }
556
557    /// Create a new HostObject var.
558    pub fn new_host_object(ptr: i32) -> Self {
559        Self::new(pxs_VarType::pxs_HostObject, pxs_VarValue{host_object_val: ptr}, default_deleter)
560    }
561
562    /// Create a new Object var.
563    pub fn new_object(ptr: pxs_VarObject, deleter: Option<pxs_DeleterFn>) -> Self {
564        let deleter = if let Some(d) = deleter {
565            d
566        } else {
567            default_deleter
568        };
569
570        Self::new(pxs_VarType::pxs_Object, pxs_VarValue { object_val: ptr.into_raw() }, deleter)
571    }
572
573    /// Create a new pxs_VarList var.
574    pub fn new_list() -> Self {
575        Self::new(pxs_VarType::pxs_List, pxs_VarValue{list_val: pxs_VarList::new().into_raw()}, default_deleter)
576    }
577
578    /// Create a new pxs_VarList var with values.
579    pub fn new_list_with(vars: Vec<pxs_Var>) -> Self {
580        let mut list = pxs_VarList::new();
581        list.vars = vars;
582        Self::new(pxs_VarType::pxs_List, pxs_VarValue{list_val: list.into_raw()}, default_deleter)
583    }
584
585    /// Create a new Function var.
586    pub fn new_function(ptr: *mut c_void, deleter: Option<pxs_DeleterFn>) -> Self {
587        let deleter = if let Some(d) = deleter {
588            d
589        } else {
590            default_deleter
591        };
592
593        Self::new(pxs_VarType::pxs_Function, pxs_VarValue { function_val: ptr }, deleter)
594    }
595
596    /// Create a new Factory var.
597    pub fn new_factory(func: super::func::pxs_Func, args: pxs_VarT) -> Self {
598        // let bvar = borrow_var!(args);
599        let factory = pxs_FactoryHolder {
600            callback: func,
601            args,
602        };
603        Self::new(pxs_VarType::pxs_Factory, pxs_VarValue{factory_val: factory.into_raw()}, default_deleter)
604    }
605
606    /// Create a new Exception var.
607    pub fn new_exception<T: ToString>(msg: T) -> Self {
608        Self::new(pxs_VarType::pxs_Exception, pxs_VarValue{string_val: create_raw_string!(msg.to_string())}, default_deleter)
609    }
610
611    /// Create a new Map var.
612    pub fn new_map() -> Self {
613        Self::new(pxs_VarType::pxs_Map, pxs_VarValue{map_val: pxs_VarMap::new().into_raw()}, default_deleter)
614    }
615
616    /// Get the IDX of the object if Host, i64, u64
617    pub fn get_host_idx(&self) -> i32 {
618        match self.tag {
619            pxs_VarType::pxs_Int64 => self.get_i64().unwrap() as i32,
620            pxs_VarType::pxs_UInt64 => self.get_u64().unwrap() as i32,
621            pxs_VarType::pxs_HostObject => unsafe { self.value.host_object_val },
622            _ => -1,
623        }
624    }
625
626    /// Get the raw pointer to a `pxs_Object` type
627    pub fn get_object_ptr(&self) -> *mut c_void {
628        match self.tag {
629            pxs_VarType::pxs_Object => unsafe {
630                let object = pxs_VarObject::from_borrow(self.value.object_val);
631                object.get_raw()
632            },
633            _ => std::ptr::null_mut(),
634        }
635    }
636
637    /// Get the pxs_VarList as a &mut pxs_VarList.
638    pub fn get_list(&self) -> Option<&mut pxs_VarList> {
639        if !self.is_list() {
640            None
641        } else {
642            unsafe { Some(pxs_VarList::from_borrow(self.value.list_val)) }
643        }
644    }
645
646    /// Get the pxs_FactoryHolder as a &mut pxs_FactoryHolder
647    pub fn get_factory(&self) -> Option<&mut pxs_FactoryHolder> {
648        if !self.is_factory() {
649            None
650        } else {
651            unsafe {
652                if self.value.factory_val.is_null() {
653                    None
654                } else {
655                    Some(pxs_FactoryHolder::from_borrow(self.value.factory_val))
656                }
657            }
658        }
659    }
660
661    /// Get the pxs_VarMap as a &mut pxs_VarMap
662    pub fn get_map(&self) -> Option<&mut pxs_VarMap> {
663        if !self.is_map() {
664            None
665        } else {
666            unsafe { Some(pxs_VarMap::from_borrow(self.value.map_val)) }
667        }
668    }
669
670    // ///
671    // pub unsafe fn from_argv(argc: usize, argv: *mut *mut pxs_Var) -> Vec<pxs_Var> {
672    //     // First create a slice
673    //     let argv_borrow = unsafe { pxs_Var::slice_raw(argv, argc) };
674    //     // Now clone them!
675    //     let cloned: Vec<pxs_Var> = argv_borrow
676    //         .iter()
677    //         .filter(|ptr| !ptr.is_null())
678    //         .map(|&ptr| unsafe { (*ptr).clone() })
679    //         .collect();
680
681    //     cloned
682    // }
683
684    /// Debug struct
685    unsafe fn dbg(&self) -> String {
686        unsafe {
687            let details = match self.tag {
688                pxs_VarType::pxs_Int64 => self.value.i64_val.to_string(),
689                pxs_VarType::pxs_UInt64 => self.value.u64_val.to_string(),
690                pxs_VarType::pxs_String => borrow_string!(self.value.string_val).to_string(),
691                pxs_VarType::pxs_Bool => self.value.bool_val.to_string(),
692                pxs_VarType::pxs_Float64 => self.value.f64_val.to_string(),
693                pxs_VarType::pxs_Null => "Null".to_string(),
694                pxs_VarType::pxs_Object => "Object".to_string(),
695                pxs_VarType::pxs_HostObject => {
696                    let idx = self.get_host_idx();
697                    let object = get_object(idx).unwrap();
698                    object.type_name.to_string()
699                }
700                pxs_VarType::pxs_List => {
701                    let list = self.get_list().unwrap();
702                    let t: String = list.vars.iter().map(|v| format!("{},", v.dbg())).collect();
703                    format!("[{t}]")
704                }
705                pxs_VarType::pxs_Function => "Function".to_string(),
706                pxs_VarType::pxs_Factory => "Factory".to_string(),
707                pxs_VarType::pxs_Exception => borrow_string!(self.value.string_val).to_string(),
708                pxs_VarType::pxs_Map => {
709                    let map = self.get_map().unwrap();
710                    let keys = map.keys();
711                    let mut res = String::from("{");
712                    for k in keys {
713                        let value = map.get_item(k);
714                        res.push_str(format!("{:#?}: {:#?},\n", k, value).as_str());
715                    }
716                    res.push_str("}");
717
718                    res
719                }
720            };
721
722            format!("{details} :: {},{} :: {:p}", self.arena, self.idx, self)
723        }
724    }
725
726    // /// Remove the deleter on current pxs_Var.
727    // pub fn remove_deleter(mut self) -> Self {
728    //     self.deleter = Cell::new(default_deleter);
729    //     self
730    // }
731
732    write_func!(
733        (get_i64, i64_val, i64, pxs_VarType::pxs_Int64),
734        (get_u64, u64_val, u64, pxs_VarType::pxs_UInt64),
735        (get_bool, bool_val, bool, pxs_VarType::pxs_Bool),
736        (get_f64, f64_val, f64, pxs_VarType::pxs_Float64),
737        (
738            get_function,
739            function_val,
740            *mut c_void,
741            pxs_VarType::pxs_Function
742        )
743    );
744
745    // $t:ty, $func:ident, $vt:expr, $vn:ident
746    write_new_methods! {
747        i64, new_i64, pxs_VarType::pxs_Int64, i64_val;
748        u64, new_u64, pxs_VarType::pxs_UInt64, u64_val;
749        f64, new_f64, pxs_VarType::pxs_Float64, f64_val;
750        bool, new_bool, pxs_VarType::pxs_Bool, bool_val
751    }
752
753    write_is_methods! {
754        is_i64, pxs_VarType::pxs_Int64;
755        is_u64, pxs_VarType::pxs_UInt64;
756        is_f64, pxs_VarType::pxs_Float64;
757        is_bool, pxs_VarType::pxs_Bool;
758        is_string, pxs_VarType::pxs_String;
759        is_null, pxs_VarType::pxs_Null;
760        is_object, pxs_VarType::pxs_Object;
761        is_host_object, pxs_VarType::pxs_HostObject;
762        is_list, pxs_VarType::pxs_List;
763        is_function, pxs_VarType::pxs_Function;
764        is_factory, pxs_VarType::pxs_Factory;
765        is_exception, pxs_VarType::pxs_Exception;
766        is_map, pxs_VarType::pxs_Map
767    }
768
769    /// Do a shallow copy on this variable.
770    /// 
771    /// Int/Uint/Float/String/Bool/Null/Exception/HostObject are cloned.
772    /// 
773    /// List/Maps/Objects/Functions/Factories are cloned without deleters.
774    pub fn shallow_copy(&self) -> pxs_Var {
775        unsafe{
776            match self.tag {
777                pxs_VarType::pxs_Int64 => self.clone(),
778                pxs_VarType::pxs_UInt64 => self.clone(),
779                pxs_VarType::pxs_String => self.clone(),
780                pxs_VarType::pxs_Bool => self.clone(),
781                pxs_VarType::pxs_Float64 => self.clone(),
782                pxs_VarType::pxs_Null => self.clone(),
783                pxs_VarType::pxs_Exception => self.clone(),
784                pxs_VarType::pxs_HostObject => self.clone(),
785                pxs_VarType::pxs_Object => {
786                    let object = pxs_VarObject::from_borrow(self.value.object_val);
787                    // Copy without deleter
788                    Self::new(pxs_VarType::pxs_Object, pxs_VarValue{object_val: object.clone().into_raw()}, default_deleter)
789                },
790                pxs_VarType::pxs_List => {
791                    let mut list = pxs_VarList::new();
792                    let og_list_val = pxs_VarList::from_borrow(self.value.list_val);
793
794                    // Shallow copy old items into new list
795                    for item in og_list_val.vars.iter() {
796                        list.add_item(item.shallow_copy());
797                    }
798
799                    Self::new(pxs_VarType::pxs_List, pxs_VarValue{list_val: list.into_raw()}, default_deleter)
800                },
801                pxs_VarType::pxs_Function => {
802                    Self::new(pxs_VarType::pxs_Function, pxs_VarValue{function_val: self.value.function_val}, default_deleter)
803                },
804                pxs_VarType::pxs_Factory => {
805                    let og = pxs_FactoryHolder::from_borrow(self.value.factory_val);
806                    if og.args.is_null() {
807                        return pxs_Var::new_null();
808                    }
809
810                    // Shallow Copy args
811                    let new_args = pxs_Var::new_list();
812                    let old_args = pxs_Var::from_borrow(og.args);
813                    if !old_args.is_list() {
814                        return pxs_Var::new_null();
815                    }
816                    let old_list = old_args.get_list().unwrap();
817                    let new_list = new_args.get_list().unwrap();
818                    for var in old_list.vars.iter() {
819                        new_list.add_item(var.shallow_copy());
820                    } 
821                    let f = pxs_FactoryHolder {
822                        args: new_args.into_raw(),
823                        callback: og.callback,
824                    };
825                    Self::new(pxs_VarType::pxs_Factory, pxs_VarValue{factory_val: f.into_raw()}, default_deleter)
826                },
827                pxs_VarType::pxs_Map => {
828                    // Our new map
829                    let mut map = pxs_VarMap::new();
830                    // OG map yo!
831                    let og_map = self.get_map().unwrap();
832                    // Get them keys dog
833                    let keys = og_map.keys();
834                    for k in keys {
835                        let v = og_map.get_item(k);
836                        if let Some(v) = v {
837                            //  shallow copy
838                            map.add_item(k.shallow_copy(), v.shallow_copy());
839                        }
840                    }
841
842                    // Follows a similar structure to pxs_List shallow copy
843                    Self::new(pxs_VarType::pxs_Map, pxs_VarValue{map_val: map.into_raw()}, default_deleter)
844                },
845            }
846        }
847    }
848
849    /// Remove this variable from it's arena.
850    pub fn remove_from_arena(&mut self) {
851        if self.idx < 0 && self.arena < 0 {
852            return;
853        }
854        remove_var_from_arena(self.arena, self.idx);
855        self.idx = -1;
856        self.arena = -1;
857    }
858}
859
860unsafe impl Send for pxs_Var {}
861unsafe impl Sync for pxs_Var {}
862
863impl Drop for pxs_Var {
864    fn drop(&mut self) {
865        if self.idx > -1 && self.arena > -1 {
866            self.remove_from_arena();
867        }
868
869        if self.tag == pxs_VarType::pxs_String || self.tag == pxs_VarType::pxs_Exception {
870            unsafe {
871                // Free the mem
872                if !self.value.string_val.is_null() {
873                    let _ = CString::from_raw(self.value.string_val);
874                    self.value.string_val = ptr::null_mut();
875                }
876            }
877        } else if self.tag == pxs_VarType::pxs_List {
878            let _ = unsafe {
879                // This will automatically drop
880                pxs_VarList::from_raw(self.value.list_val)
881            };
882        } else if self.tag == pxs_VarType::pxs_Object {
883            unsafe {
884                if self.value.object_val.is_null() {
885                    return;
886                }
887                let object = pxs_VarObject::from_raw(self.value.object_val);
888                (self.deleter.get())(object.get_raw());
889                // object dropped here.
890            };
891        } else if self.tag == pxs_VarType::pxs_Function {
892            unsafe {
893                if self.value.object_val.is_null() {
894                    return;
895                }
896                (self.deleter.get())(self.value.function_val)
897            };
898        } else if self.tag == pxs_VarType::pxs_Factory {
899            // Free args
900            unsafe {
901                if self.value.factory_val.is_null() {
902                    return;
903                }
904                let _ = pxs_FactoryHolder::from_raw(self.value.factory_val);
905                // if val.args.is_null() {
906                //     return;
907                // }
908                // // Drop list
909                // let _ = pxs_Var::from_raw(val.args);
910            }
911        } else if self.tag == pxs_VarType::pxs_Map {
912            let _ = unsafe {
913                pxs_VarMap::from_raw(self.value.map_val)
914            };
915        }
916    }
917}
918
919impl PtrMagic for pxs_Var {
920    // Override the `into_raw` for pxs_Var so we save in the arena.
921    fn into_raw(self) -> *mut Self {
922        let arena = get_current_arena_id();
923        let ptr = Box::into_raw(Box::new(self));
924
925        // Save in arena
926        save_var_in_arena(arena, ptr);
927
928        ptr
929    }
930}
931
932impl Clone for pxs_Var {
933    fn clone(&self) -> Self {
934        unsafe {
935            match self.tag {
936                pxs_VarType::pxs_Int64 => pxs_Var::new_i64(self.value.i64_val),
937                pxs_VarType::pxs_UInt64 => pxs_Var::new_u64(self.value.u64_val),
938                pxs_VarType::pxs_String => {
939                    let string = borrow_string!(self.value.string_val);
940                    let cloned_string = string.to_string().clone();
941                    let new_string = create_raw_string!(cloned_string);
942
943                    Self::new(pxs_VarType::pxs_String, pxs_VarValue{string_val: new_string}, default_deleter)
944                }
945                pxs_VarType::pxs_Bool => pxs_Var::new_bool(self.value.bool_val),
946                pxs_VarType::pxs_Float64 => pxs_Var::new_f64(self.value.f64_val),
947                pxs_VarType::pxs_Null => pxs_Var::new_null(),
948                pxs_VarType::pxs_Object => {
949                    let object = pxs_VarObject::from_borrow(self.value.object_val);
950
951                    // Move deleter to this object.
952                    let r = Self::new(pxs_VarType::pxs_Object, pxs_VarValue{object_val: object.clone().into_raw()}, self.deleter.get());
953
954                    self.deleter.set(default_deleter);
955
956                    r
957                }
958                pxs_VarType::pxs_HostObject => pxs_Var::new_host_object(self.value.host_object_val),
959                pxs_VarType::pxs_List => {
960                    let mut list = pxs_VarList::new();
961                    // let mut list = pxs_Var::new_list();
962                    let og_list_val = pxs_VarList::from_borrow(self.value.list_val);
963
964                    // Add items of current list. i.e. transfer ownership...
965                    for item in og_list_val.vars.iter() {
966                        // Clone into new list
967                        list.add_item(item.clone());
968                    }
969
970                    Self::new(pxs_VarType::pxs_List, pxs_VarValue{ list_val: list.into_raw()}, default_deleter)
971                }
972                pxs_VarType::pxs_Function => {
973                    let r = Self::new(pxs_VarType::pxs_Function, pxs_VarValue{function_val: self.value.function_val}, self.deleter.get());
974
975                    self.deleter.set(default_deleter);
976                    r
977                }
978                pxs_VarType::pxs_Factory => {
979                    let og = pxs_FactoryHolder::from_borrow(self.value.factory_val);
980                    if og.args.is_null() {
981                        return pxs_Var::new_null();
982                    }
983                    // Clone args
984                    let new_args = pxs_Var::new_list();
985                    let old_args = pxs_Var::from_borrow(og.args);
986                    if !old_args.is_list() {
987                        return pxs_Var::new_null();
988                    }
989                    let old_list = old_args.get_list().unwrap();
990                    let new_list = new_args.get_list().unwrap();
991                    for var in old_list.vars.iter() {
992                        new_list.add_item(var.clone());
993                    }
994                    let f = pxs_FactoryHolder {
995                        args: new_args.into_raw(),
996                        callback: og.callback,
997                    };
998                    Self::new(pxs_VarType::pxs_Factory, pxs_VarValue{factory_val: f.into_raw()}, default_deleter)
999                }
1000                pxs_VarType::pxs_Exception => {
1001                    let string = borrow_string!(self.value.string_val);
1002                    let cloned_string = string.to_string().clone();
1003                    let new_string = create_raw_string!(cloned_string);
1004                    Self::new(pxs_VarType::pxs_Exception, pxs_VarValue{string_val: new_string}, default_deleter)
1005                }
1006                pxs_VarType::pxs_Map => {
1007                    // Our new map
1008                    let mut map = pxs_VarMap::new();
1009                    // OG map yo!
1010                    let og_map = self.get_map().unwrap();
1011                    // Get them keys dog
1012                    let keys = og_map.keys();
1013                    for k in keys {
1014                        let v = og_map.get_item(k);
1015                        if let Some(v) = v {
1016                            map.add_item(k.clone(), v.clone());
1017                        }
1018                    }
1019
1020                    // Follows a similar structure to pxs_List cloning
1021                    Self::new(pxs_VarType::pxs_Map, pxs_VarValue{map_val: map.into_raw()}, default_deleter)
1022                }
1023            }
1024        }
1025    }
1026}
1027
1028impl std::fmt::Debug for pxs_Var {
1029    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1030        let debug_val: &dyn std::fmt::Debug = unsafe { &self.dbg() };
1031        f.debug_struct("pxs_Var")
1032            .field("tag", &self.tag)
1033            .field("value", debug_val)
1034            .finish()
1035    }
1036}
1037
1038impl PartialEq for pxs_Var {
1039    fn eq(&self, other: &Self) -> bool {
1040        unsafe {
1041            match (&self.tag, &other.tag) {
1042                (pxs_VarType::pxs_Int64, pxs_VarType::pxs_Int64) => {
1043                    self.value.i64_val == other.value.i64_val
1044                }
1045                (pxs_VarType::pxs_Int64, _) => false,
1046                (pxs_VarType::pxs_UInt64, pxs_VarType::pxs_UInt64) => {
1047                    self.value.u64_val == other.value.u64_val
1048                }
1049                (pxs_VarType::pxs_UInt64, _) => false,
1050                (pxs_VarType::pxs_String, pxs_VarType::pxs_String) => {
1051                    self.get_string().unwrap_or(String::new())
1052                        == other.get_string().unwrap_or(String::new())
1053                }
1054                (pxs_VarType::pxs_String, _) => false,
1055                (pxs_VarType::pxs_Bool, pxs_VarType::pxs_Bool) => {
1056                    self.value.bool_val == other.value.bool_val
1057                }
1058                (pxs_VarType::pxs_Bool, _) => false,
1059                (pxs_VarType::pxs_Float64, pxs_VarType::pxs_Float64) => {
1060                    self.value.f64_val == other.value.f64_val
1061                }
1062                (pxs_VarType::pxs_Float64, _) => false,
1063                (pxs_VarType::pxs_Null, _) => false,
1064                (pxs_VarType::pxs_Object, _) => false,
1065                (pxs_VarType::pxs_HostObject, _) => false,
1066                (pxs_VarType::pxs_List, _) => false,
1067                (pxs_VarType::pxs_Function, _) => false,
1068                (pxs_VarType::pxs_Factory, _) => false,
1069                (pxs_VarType::pxs_Exception, _) => false,
1070                (pxs_VarType::pxs_Map, _) => false,
1071            }
1072        }
1073    }
1074}
1075
1076impl Eq for pxs_Var {}
1077
1078impl Hash for pxs_Var {
1079    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1080        unsafe {
1081            match self.tag {
1082                pxs_VarType::pxs_Int64 => self.value.i64_val.hash(state),
1083                pxs_VarType::pxs_UInt64 => self.value.u64_val.hash(state),
1084                pxs_VarType::pxs_String => self.get_string().unwrap_or(String::new()).hash(state),
1085                pxs_VarType::pxs_Bool => self.value.bool_val.hash(state),
1086                pxs_VarType::pxs_Float64 => self.value.f64_val.to_bits().hash(state),
1087                _ => panic!("Can not Hash none basic pxs_VarType")
1088            }
1089        }
1090    }
1091}
1092
1093impl pxs_Var {
1094    /// Return a error saying that the found type was not expected.
1095    pub fn incorrect_type_ep(expected: pxs_VarType, found: pxs_VarType) -> Self {
1096        Self::new_exception(format!("Expected {:#?}, found {:#?}", expected, found))
1097    }
1098    
1099    /// Return a error saying that the found type was not expected of a vector of types
1100    pub fn incorrect_types_ep(allowed: Vec<pxs_VarType>, found: pxs_VarType) -> Self {
1101        Self::new_exception(format!("Allowed types: {:#?}, found: {:#?}", allowed, found))
1102    }
1103
1104    /// A general error saying that paramaters passed in to the function were null.
1105    pub fn null_params_ep() -> Self {
1106        Self::new_exception("Paramaters are null")
1107    }
1108
1109    /// A specific error that a specific param was null.
1110    pub fn null_param_ep<T: ToString>(name:T) -> Self {
1111        Self::new_exception(format!("{} is null", name.to_string()))
1112    }
1113
1114    /// Unkownn runtime exception
1115    pub fn unkown_runtime_ep(runtime: i64) -> Self {
1116        Self::new_exception(format!("Unkown runtime: {runtime}"))
1117    }
1118
1119    /// Unkown runtime var exception
1120    pub fn unkown_runtime_var_ep(runtime: pxs_VarT) -> Self {
1121        let var = unsafe{Self::from_borrow(runtime)};
1122        Self::new_exception(format!("Unkown runtime: {:#?}", var))
1123    }
1124
1125    /// When a item is not found in list or map.
1126    pub fn item_not_found_ep() -> Self {
1127        Self::new_exception("Item not found")
1128    }
1129
1130    /// Feature not enabled
1131    pub fn feature_not_enabled_ep(feature: &str) -> Self {
1132        Self::new_exception(format!("{feature} is not enabled."))
1133    }
1134}
1135
1136/// Methods for interacting with objects and callbacks from the runtime.
1137pub trait ObjectMethods {
1138    /// Call a method on a object.
1139    fn object_call(var: &pxs_Var, method: &str, args: &mut pxs_VarList) -> Result<pxs_Var, Error>;
1140
1141    /// Call a method and pass in args
1142    fn call_method(method: &str, args: &mut pxs_VarList) -> Result<pxs_Var, Error>;
1143
1144    /// Call a pxs_Var function.
1145    fn var_call(method: &pxs_Var, args: &mut pxs_VarList) -> Result<pxs_Var, Error>;
1146
1147    /// Getter
1148    fn get(var: &pxs_Var, key: &str) -> Result<pxs_Var, Error>;
1149
1150    /// Setter
1151    fn set(var: &pxs_Var, key: &str, value: &pxs_Var) -> Result<pxs_Var, Error>;
1152
1153    /// Get a object/function based off their name
1154    fn get_from_name(name: &str) -> Result<pxs_Var, Error>;
1155}
1156
1157/// Type Helper for a pxs_Var
1158/// Use this instead of writing out pxs_Var*
1159#[allow(non_camel_case_types)]
1160pub type pxs_VarT = *mut pxs_Var;