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    ffi::{CStr, CString, c_char, c_void},
12    ptr,
13};
14
15use anyhow::{Error, anyhow};
16
17use crate::{
18    borrow_string, create_raw_string, pxs_debug, shared::{
19        PtrMagic,
20        object::get_object, pxs_Runtime,
21    }
22};
23
24/// Macro for writing out the Var:: get methods.
25macro_rules! write_func {
26    ($ (($func_name:ident, $field_name:ident, $ret_type:ty, $tag_variant:path) ),* $(,)?) => {
27        $(
28            #[doc = concat!("Returns the ", stringify!($ret_type), " value if the tag is ", stringify!($tag_variant), ".")]
29            pub fn $func_name(&self) -> Result<$ret_type, Error> {
30                if self.tag == $tag_variant {
31                    unsafe {
32                        Ok(self.value.$field_name)
33                    }
34                } else {
35                    Err(anyhow!("Var is not the expected type of {:#?}. It is instead a: {:#?}", $tag_variant, self.tag))
36                }
37            }
38        )*
39    };
40}
41
42/// Macro for writing out the new_t methods in Var
43macro_rules! write_new_methods {
44    ($($t:ty, $func:ident, $vt:expr, $vn:ident);*) => {
45        $(
46            pub fn $func(val:$t) -> Self {
47                Self {
48                    tag: $vt,
49                    value: pxs_VarValue { $vn: val },
50                    deleter: Cell::new(default_deleter)
51                }
52            }
53        )*
54    };
55}
56
57/// Macro for writing out the is_t methods in Var
58macro_rules! write_is_methods {
59    ($($func:ident, $vt:expr);*) => {
60        $(
61            pub fn $func(&self) -> bool {
62                self.tag == $vt
63            }
64        )*
65    };
66}
67
68// // Macro for writing out the FromVars
69// macro_rules! implement_from_var {
70//     ($($t:ty, $func:ident);*) => {
71//         $(
72//             impl FromVar for $t {
73//                 fn from_var(var:&Var) -> Result<Self, Error> {
74//                     var.$func()
75//                 }
76//             }
77//         )*
78//     };
79// }
80
81/// This represents the variable type that is being read or created.
82#[repr(C)]
83#[derive(Debug, PartialEq, Clone)]
84#[allow(non_camel_case_types)]
85pub enum pxs_VarType {
86    pxs_Int64,
87    pxs_UInt64,
88    pxs_String,
89    pxs_Bool,
90    pxs_Float64,
91    /// Lua (nil), Python (None), JS/easyjs (null/undefined)
92    pxs_Null,
93    /// Lua (Tree), Python (Class), JS/easyjs (Prototype)
94    pxs_Object,
95    /// Host object converted when created.
96    /// Lua (Tree), Python (object), JS/easyjs (Prototype think '{}')
97    pxs_HostObject,
98    /// Lua (Tree), Python (list), JS/easyjs (Array)
99    pxs_List,
100    /// Lua (Value), Python (def or lambda), JS/easyjs (anon function)
101    pxs_Function,
102    /// Internal object only. It will get converted into the result before hitting the runtime
103    pxs_Factory,
104}
105
106/// A Factory variable data holder.
107/// 
108/// Holds a callback for creation. And the arguments to be supplied. 
109/// Runtime will be supplied automatically.
110#[allow(non_camel_case_types)]
111pub struct pxs_FactoryHolder {
112    pub callback: super::func::pxs_Func,
113    pub args: *mut pxs_Var
114}
115
116impl pxs_FactoryHolder {
117    /// Get a cloned list of args. This list will include the runtime passed as the
118    /// first item. Returns a owned pxs_Var not a pointer.
119    pub fn get_args(&self, rt: pxs_Runtime) -> pxs_Var {
120        let args = self.args;
121        // Check null
122        assert!(!args.is_null(), "Factory args must not be null");
123        unsafe {
124            // Clone
125            let args_clone = pxs_Var::from_borrow(self.args).clone();
126            // Check list
127            assert!(args_clone.is_list(), "Factory args must be a list");
128            // Get list and add runtime
129            let args_list = args_clone.get_list().unwrap();
130            args_list.vars.insert(0, pxs_Var::new_i64(rt.into_i64()));
131
132            args_clone
133        }
134    }
135
136    /// Call the FactoryHolder function with the args!
137    pub fn call(&self, rt: pxs_Runtime) -> pxs_Var {
138        let args = self.get_args(rt);
139        // Create raw memory that lasts for the direction of this call.
140        let args_raw = args.into_raw();
141
142        let res = unsafe {(self.callback)(args_raw, ptr::null_mut()) };
143        let var = if res.is_null() {
144            pxs_Var::new_null()
145        } else {
146            pxs_Var::from_raw(res)
147        };
148        // Drop raw args memory
149        let _ = pxs_Var::from_raw(args_raw);
150
151        // Return the variable result
152        var
153    }
154}
155// impl pxs_FactoryHolder {
156//     /// Call the callback with args and null ptr
157//     pub unsafe fn get_result(&mut self, rt: pxs_Runtime) -> pxs_VarT {
158//         let args = unsafe{ pxs_Var::from_borrow(self.args) };
159//         let list = args.get_list().unwrap();
160//         if !self.has_rt {
161//             pxs_debug!("Adding the runtime. Current length: {}", list.vars.len());
162//             self.has_rt = true;
163//             list.vars.insert(0, pxs_Var::new_i64(rt.into_i64()));
164//         } else {
165//             pxs_debug!("Resetting the runtime.");
166//             list.set_item(pxs_Var::new_i64(rt.into_i64()), 0);
167//         }
168//         unsafe { (self.callback)(self.args, std::ptr::null_mut()) }
169//     }
170// }
171
172impl PtrMagic for pxs_FactoryHolder {}
173
174/// Holds data for a pxs_Var of list.
175///
176/// It holds multiple pxsVar within.
177///
178/// When creating call:
179///
180/// `pixelscript_var_newlist()`.
181///
182/// To add items
183///
184/// `pixelscript_var_list_add(list_ptr, item_ptr)`
185///
186/// To get items
187///
188/// `pixelscript_var_list_get(list_ptr, index)`
189///
190/// A full example looks like:
191/// ```c
192/// // Create a new list (you never interact with pxs_VarList directly...)
193/// pxs_Var* list = pixelscript_var_newlist();
194///
195/// // Add a item
196/// pxs_Var* number = pixelscript_var_newint(1);
197/// pixelscript_var_list_add(list, number);
198///
199/// // Get a item
200/// pxs_Var* item_got = pixelscript_var_list_get(list, 0);
201/// ```
202#[allow(non_camel_case_types)]
203pub struct pxs_VarList {
204    pub vars: Vec<pxs_Var>,
205}
206
207impl PtrMagic for pxs_VarList {}
208
209impl pxs_VarList {
210    /// Create a new VarList
211    pub fn new() -> Self {
212        pxs_VarList { vars: vec![] }
213    }
214
215    /// Add a Var to the list. List will take ownership.
216    pub fn add_item(&mut self, item: pxs_Var) {
217        self.vars.push(item);
218    }
219
220    /// Get a Var from the list. Supports negative based indexes.
221    pub fn get_item(&self, index: i32) -> Option<&pxs_Var> {
222        // Get correct negative index.
223        let r_index = {
224            if index < 0 {
225                (self.vars.len() as i32) + index
226            } else {
227                index
228            }
229        };
230
231        if r_index < 0 {
232            None
233        } else {
234            self.vars.get(r_index as usize)
235        }
236    }
237
238    /// Set at a specific index a item.
239    ///
240    /// Index must already be filled.
241    pub fn set_item(&mut self, item: pxs_Var, index: i32) -> bool {
242        // Get correct negative index.
243        let r_index = {
244            if index < 0 {
245                (self.vars.len() as i32) + index
246            } else {
247                index
248            }
249        };
250
251        if r_index < 0 {
252            return false;
253        }
254
255        if self.vars.len() < r_index as usize {
256            false
257        } else {
258            self.vars[r_index as usize] = item;
259            true
260        }
261    }
262}
263
264/// The Variables actual value union.
265#[repr(C)]
266#[allow(non_camel_case_types)]
267pub union pxs_VarValue {
268    pub i64_val: i64,
269    pub u64_val: u64,
270    pub string_val: *mut c_char,
271    pub bool_val: bool,
272    pub f64_val: f64,
273    pub null_val: *const c_void,
274    pub object_val: *mut c_void,
275    pub host_object_val: i32,
276    pub list_val: *mut pxs_VarList,
277    pub function_val: *mut c_void,
278    pub factory_val: *mut pxs_FactoryHolder,
279}
280
281#[allow(non_camel_case_types)]
282pub type pxs_DeleterFn = unsafe extern "C" fn(*mut c_void);
283
284/// Default Var deleter fn.
285/// Use it when you don't want to delete memory.
286pub unsafe extern "C" fn default_deleter(_ptr: *mut c_void) {
287    // Empty OP
288}
289
290/// A PixelScript Var(iable).
291///
292/// This is the universal truth between all languages PixelScript supports.
293///
294/// Currently supports:
295/// - int (i32, i64, u32, u64)
296/// - float (f32, f64)
297/// - string
298/// - boolean
299/// - Objects
300/// - HostObjects (C structs acting as pseudo-classes) This in the Host can also be a Int or Uint.
301/// - List
302/// - Functions (First class functions)
303///
304/// When working with objects you must use the C-api:
305/// ```c
306/// // Calls a method on a object.
307/// pixelscript_object_call(var)
308/// ```
309///
310/// When using within a callback, if said callback was attached to a Class, the first *mut Var will be the class/object.
311///
312/// When using ints or floats, if (i32, u32, u64, f32) there is no gurantee that the supported language uses
313/// those types. Usually it defaults to i64 and f64.
314///
315/// When creating a object, this is a bit tricky but essentially you have to first create a pointer via the pixel script runtime.
316#[repr(C)]
317#[allow(non_camel_case_types)]
318pub struct pxs_Var {
319    /// A tag for the variable type.
320    pub tag: pxs_VarType,
321    /// A value as a union.
322    pub value: pxs_VarValue,
323
324    /// Optional delete method. This is used for Pointers in Objects, and Functions.
325    pub deleter: Cell<pxs_DeleterFn>,
326}
327
328// Rust specific functions
329impl pxs_Var {
330    pub unsafe fn slice_raw(argv: *mut *mut Self, argc: usize) -> &'static [*mut pxs_Var] {
331        unsafe { std::slice::from_raw_parts(argv, argc) }
332    }
333
334    /// Get the direct host pointer. (Not the idx)
335    pub fn get_host_ptr(&self) -> *mut c_void {
336        let object = get_object(self.get_object_ptr()).unwrap();
337        object.ptr
338    }
339
340    /// Get the Rust string from the Var.
341    pub fn get_string(&self) -> Result<String, Error> {
342        if self.tag == pxs_VarType::pxs_String {
343            unsafe {
344                if self.value.string_val.is_null() {
345                    return Err(anyhow!("String pointer is null"));
346                }
347
348                let c_str = CStr::from_ptr(self.value.string_val);
349                let res = c_str.to_str();
350                if res.is_err() {
351                    return Err(anyhow!(res.err().unwrap()));
352                }
353
354                Ok(res.unwrap().to_string())
355            }
356        } else {
357            Err(anyhow!("Var is not a string."))
358        }
359    }
360
361    /// Create a new String var.
362    ///
363    /// The memory is leaked and needs to be freed eventually. It is freed by Var::free_var(). And done so automatically
364    /// by the library.
365    pub fn new_string(val: String) -> Self {
366        let cstr = CString::new(val).expect("Could not create CString.");
367
368        pxs_Var {
369            tag: pxs_VarType::pxs_String,
370            value: pxs_VarValue {
371                string_val: cstr.into_raw(),
372            },
373            deleter: Cell::new(default_deleter),
374        }
375    }
376
377    /// Creates a new Null var.
378    ///
379    /// No need to free, or any of that. It cretes a *const c_void
380    pub fn new_null() -> Self {
381        pxs_Var {
382            tag: pxs_VarType::pxs_Null,
383            value: pxs_VarValue {
384                null_val: ptr::null(),
385            },
386            deleter: Cell::new(default_deleter),
387        }
388    }
389
390    /// Create a new HostObject var.
391    pub fn new_host_object(ptr: i32) -> Self {
392        pxs_Var {
393            tag: pxs_VarType::pxs_HostObject,
394            value: pxs_VarValue {
395                host_object_val: ptr,
396            },
397            deleter: Cell::new(default_deleter),
398        }
399    }
400
401    /// Create a new Object var.
402    pub fn new_object(ptr: *mut c_void, deleter: Option<pxs_DeleterFn>) -> Self {
403        let deleter = if let Some(d) = deleter {
404            d
405        } else {
406            default_deleter
407        };
408        pxs_Var {
409            tag: pxs_VarType::pxs_Object,
410            value: pxs_VarValue { object_val: ptr },
411            deleter: Cell::new(deleter),
412        }
413    }
414
415    /// Create a new pxs_VarList var.
416    pub fn new_list() -> Self {
417        pxs_Var {
418            tag: pxs_VarType::pxs_List,
419            value: pxs_VarValue {
420                list_val: pxs_VarList::new().into_raw(),
421            },
422            deleter: Cell::new(default_deleter),
423        }
424    }
425
426    /// Create a new pxs_VarList var with values.
427    pub fn new_list_with(vars: Vec<pxs_Var>) -> Self {
428        let mut list = pxs_VarList::new();
429        list.vars = vars;
430        pxs_Var {
431            tag: pxs_VarType::pxs_List,
432            value: pxs_VarValue {
433                list_val: list.into_raw(),
434            },
435            deleter: Cell::new(default_deleter),
436        }
437    }
438
439    /// Create a new Function var.
440    pub fn new_function(ptr: *mut c_void, deleter: Option<pxs_DeleterFn>) -> Self {
441        let deleter = if let Some(d) = deleter {
442            d
443        } else {
444            default_deleter
445        };
446
447        pxs_Var {
448            tag: pxs_VarType::pxs_Function,
449            value: pxs_VarValue { function_val: ptr },
450            deleter: Cell::new(deleter),
451        }
452    }
453
454    /// Create a new Factory var.
455    pub fn new_factory(func: super::func::pxs_Func, args: pxs_VarT) -> Self {
456        let factory = pxs_FactoryHolder {
457            callback: func,
458            args
459        };
460        pxs_Var {
461            tag: pxs_VarType::pxs_Factory,
462            value: pxs_VarValue {
463                factory_val: factory.into_raw(),
464            },
465            deleter: Cell::new(default_deleter),
466        }
467    }
468    //     name: *const c_char,
469    // func: pxs_Func,
470    // args: *mut pxs_Var
471
472    /// Get the ptr of the object if Host, i32, i64, u32, u64
473    pub fn get_object_ptr(&self) -> i32 {
474        match self.tag {
475            pxs_VarType::pxs_Int64 => self.get_i64().unwrap() as i32,
476            pxs_VarType::pxs_UInt64 => self.get_u64().unwrap() as i32,
477            pxs_VarType::pxs_HostObject => unsafe { self.value.host_object_val },
478            _ => -1,
479        }
480    }
481
482    /// Get the pxs_VarList as a &mut pxs_VarList.
483    pub fn get_list(&self) -> Option<&mut pxs_VarList> {
484        if !self.is_list() {
485            None
486        } else {
487            unsafe { Some(pxs_VarList::from_borrow(self.value.list_val)) }
488        }
489    }
490
491    /// Get the pxs_FactoryHolder as a &mut pxs_FactoryHolder
492    pub fn get_factory(&self) -> Option<&mut pxs_FactoryHolder> {
493        if !self.is_factory() {
494            None
495        } else {
496            unsafe {
497                if self.value.factory_val.is_null() {
498                    None
499                } else {
500                    Some(pxs_FactoryHolder::from_borrow(self.value.factory_val))
501                }
502            }
503        }
504    }
505
506    ///
507    pub unsafe fn from_argv(argc: usize, argv: *mut *mut pxs_Var) -> Vec<pxs_Var> {
508        // First create a slice
509        let argv_borrow = unsafe { pxs_Var::slice_raw(argv, argc) };
510        // Now clone them!
511        let cloned: Vec<pxs_Var> = argv_borrow
512            .iter()
513            .filter(|ptr| !ptr.is_null())
514            .map(|&ptr| unsafe { (*ptr).clone() })
515            .collect();
516
517        cloned
518    }
519
520    /// Debug struct
521    unsafe fn dbg(&self) -> String {
522        unsafe {
523            let details = match self.tag {
524                pxs_VarType::pxs_Int64 => self.value.i64_val.to_string(),
525                pxs_VarType::pxs_UInt64 => self.value.u64_val.to_string(),
526                pxs_VarType::pxs_String => borrow_string!(self.value.string_val).to_string(),
527                pxs_VarType::pxs_Bool => self.value.bool_val.to_string(),
528                pxs_VarType::pxs_Float64 => self.value.f64_val.to_string(),
529                pxs_VarType::pxs_Null => "Null".to_string(),
530                pxs_VarType::pxs_Object => "Object".to_string(),
531                pxs_VarType::pxs_HostObject => {
532                    let idx = self.get_object_ptr();
533                    let object = get_object(idx).unwrap();
534                    object.type_name.to_string()
535                }
536                pxs_VarType::pxs_List => {
537                    let list = self.get_list().unwrap();
538                    let t: String = list.vars.iter().map(|v| format!("{},", v.dbg())).collect();
539                    format!("[{t}]")
540                }
541                pxs_VarType::pxs_Function => "Function".to_string(),
542                pxs_VarType::pxs_Factory => "Factory".to_string(),
543            };
544
545            format!("{details} :: {:p}", self)
546        }
547    }
548
549    /// Remove the deleter on current pxs_Var.
550    pub fn remove_deleter(mut self) -> Self {
551        self.deleter = Cell::new(default_deleter);
552        self
553    }
554
555    write_func!(
556        (get_i64, i64_val, i64, pxs_VarType::pxs_Int64),
557        (get_u64, u64_val, u64, pxs_VarType::pxs_UInt64),
558        (get_bool, bool_val, bool, pxs_VarType::pxs_Bool),
559        (get_f64, f64_val, f64, pxs_VarType::pxs_Float64),
560        (
561            get_function,
562            function_val,
563            *mut c_void,
564            pxs_VarType::pxs_Function
565        )
566    );
567
568    // $t:ty, $func:ident, $vt:expr, $vn:ident
569    write_new_methods! {
570        i64, new_i64, pxs_VarType::pxs_Int64, i64_val;
571        u64, new_u64, pxs_VarType::pxs_UInt64, u64_val;
572        f64, new_f64, pxs_VarType::pxs_Float64, f64_val;
573        bool, new_bool, pxs_VarType::pxs_Bool, bool_val
574    }
575
576    write_is_methods! {
577        is_i64, pxs_VarType::pxs_Int64;
578        is_u64, pxs_VarType::pxs_UInt64;
579        is_f64, pxs_VarType::pxs_Float64;
580        is_bool, pxs_VarType::pxs_Bool;
581        is_string, pxs_VarType::pxs_String;
582        is_null, pxs_VarType::pxs_Null;
583        is_object, pxs_VarType::pxs_Object;
584        is_host_object, pxs_VarType::pxs_HostObject;
585        is_list, pxs_VarType::pxs_List;
586        is_function, pxs_VarType::pxs_Function;
587        is_factory, pxs_VarType::pxs_Factory
588    }
589}
590
591unsafe impl Send for pxs_Var {}
592unsafe impl Sync for pxs_Var {}
593
594impl Drop for pxs_Var {
595    fn drop(&mut self) {
596        // pxs_debug!("|psx_Var DROP| {}", unsafe {self.dbg() });
597        if self.tag == pxs_VarType::pxs_String {
598            unsafe {
599                // Free the mem
600                if !self.value.string_val.is_null() {
601                    let _ = CString::from_raw(self.value.string_val);
602                    self.value.string_val = ptr::null_mut();
603                }
604            }
605        } else if self.tag == pxs_VarType::pxs_List {
606            let _ = unsafe {
607                // This will automatically drop
608                pxs_VarList::from_raw(self.value.list_val)
609            };
610        } else if self.tag == pxs_VarType::pxs_Object {
611            unsafe {
612                if self.value.object_val.is_null() {
613                    return;
614                }
615                (self.deleter.get())(self.value.object_val)
616            };
617        } else if self.tag == pxs_VarType::pxs_Function {
618            unsafe {
619                if self.value.object_val.is_null() {
620                    return;
621                }
622                (self.deleter.get())(self.value.object_val)
623            };
624        } else if self.tag == pxs_VarType::pxs_Factory {
625            // Free args
626            unsafe {
627                if self.value.factory_val.is_null() {
628                    return;
629                }
630                let val = pxs_FactoryHolder::from_borrow(self.value.factory_val);
631                if val.args.is_null() {
632                    return;
633                }
634                // Drop list
635                let _ = pxs_Var::from_raw(val.args);
636            }
637        }
638    }
639}
640
641impl PtrMagic for pxs_Var {}
642
643impl Clone for pxs_Var {
644    fn clone(&self) -> Self {
645        unsafe {
646            match self.tag {
647                pxs_VarType::pxs_Int64 => pxs_Var::new_i64(self.value.i64_val),
648                pxs_VarType::pxs_UInt64 => pxs_Var::new_u64(self.value.u64_val),
649                pxs_VarType::pxs_String => {
650                    let string = borrow_string!(self.value.string_val);
651                    let cloned_string = string.to_string().clone();
652                    let new_string = create_raw_string!(cloned_string);
653                    pxs_Var {
654                        tag: pxs_VarType::pxs_String,
655                        value: pxs_VarValue {
656                            string_val: new_string,
657                        },
658                        deleter: Cell::new(default_deleter),
659                    }
660                }
661                pxs_VarType::pxs_Bool => pxs_Var::new_bool(self.value.bool_val),
662                pxs_VarType::pxs_Float64 => pxs_Var::new_f64(self.value.f64_val),
663                pxs_VarType::pxs_Null => pxs_Var::new_null(),
664                pxs_VarType::pxs_Object => {
665                    let r = pxs_Var {
666                        tag: pxs_VarType::pxs_Object,
667                        value: pxs_VarValue {
668                            object_val: self.value.object_val,
669                        },
670                        deleter: Cell::new(self.deleter.get()),
671                    };
672
673                    self.deleter.set(default_deleter);
674
675                    r
676                }
677                pxs_VarType::pxs_HostObject => pxs_Var::new_host_object(self.value.host_object_val),
678                pxs_VarType::pxs_List => {
679                    let mut list = pxs_VarList::new();
680                    // let mut list = pxs_Var::new_list();
681                    let og_list_val = pxs_VarList::from_borrow(self.value.list_val);
682
683                    // Add items of current list. i.e. transfer ownership...
684                    for item in og_list_val.vars.iter() {
685                        // Clone into new list
686                        list.add_item(item.clone());
687                    }
688
689                    pxs_Var {
690                        tag: pxs_VarType::pxs_List,
691                        value: pxs_VarValue {
692                            list_val: list.into_raw(),
693                        },
694                        deleter: Cell::new(default_deleter),
695                    }
696                }
697                pxs_VarType::pxs_Function => {
698                    let r = pxs_Var {
699                        tag: pxs_VarType::pxs_Function,
700                        value: pxs_VarValue {
701                            function_val: self.value.function_val,
702                        },
703                        deleter: Cell::new(self.deleter.get()),
704                    };
705
706                    self.deleter.set(default_deleter);
707                    r
708                }
709                pxs_VarType::pxs_Factory => {
710                    let og = pxs_FactoryHolder::from_borrow(self.value.factory_val);
711                    if og.args.is_null() {
712                        return pxs_Var::new_null();
713                    }
714                    // Clone args
715                    let new_args = pxs_Var::new_list();
716                    let old_args = pxs_Var::from_borrow(og.args);
717                    if !old_args.is_list() {
718                        return pxs_Var::new_null();
719                    }
720                    let old_list = old_args.get_list().unwrap();
721                    let new_list = new_args.get_list().unwrap();
722                    for var in old_list.vars.iter() {
723                        new_list.add_item(var.clone());
724                    }
725                    let f = pxs_FactoryHolder {
726                        args: new_args.into_raw(),
727                        callback: og.callback
728                    };
729                    pxs_Var {
730                        tag: pxs_VarType::pxs_Factory,
731                        value: pxs_VarValue {
732                            factory_val: f.into_raw(),
733                        },
734                        deleter: Cell::new(default_deleter),
735                    }
736                }
737            }
738        }
739    }
740}
741
742impl std::fmt::Debug for pxs_Var {
743    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
744        let debug_val: &dyn std::fmt::Debug = unsafe { &self.dbg() };
745        f.debug_struct("pxs_Var")
746            .field("tag", &self.tag)
747            .field("value", debug_val)
748            .finish()
749    }
750}
751
752/// Methods for interacting with objects and callbacks from the runtime.
753pub trait ObjectMethods {
754    /// Call a method on a object.
755    fn object_call(var: &pxs_Var, method: &str, args: &mut pxs_VarList) -> Result<pxs_Var, Error>;
756
757    /// Call a method and pass in args
758    fn call_method(method: &str, args: &mut pxs_VarList) -> Result<pxs_Var, Error>;
759
760    /// Call a pxs_Var function.
761    fn var_call(method: &pxs_Var, args: &mut pxs_VarList) -> Result<pxs_Var, Error>;
762
763    /// Getter
764    fn get(var: &pxs_Var, key: &str) -> Result<pxs_Var, Error>;
765
766    /// Setter
767    fn set(var: &pxs_Var, key: &str, value: &pxs_Var) -> Result<pxs_Var, Error>;
768}
769
770/// Type Helper for a pxs_Var
771/// Use this instead of writing out pxs_Var*
772#[allow(non_camel_case_types)]
773pub type pxs_VarT = *mut pxs_Var;