1use 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
24macro_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
42macro_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
57macro_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#[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 pxs_Null,
93 pxs_Object,
95 pxs_HostObject,
98 pxs_List,
100 pxs_Function,
102 pxs_Factory,
104}
105
106#[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 pub fn get_args(&self, rt: pxs_Runtime) -> pxs_Var {
120 let args = self.args;
121 assert!(!args.is_null(), "Factory args must not be null");
123 unsafe {
124 let args_clone = pxs_Var::from_borrow(self.args).clone();
126 assert!(args_clone.is_list(), "Factory args must be a list");
128 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 pub fn call(&self, rt: pxs_Runtime) -> pxs_Var {
138 let args = self.get_args(rt);
139 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 let _ = pxs_Var::from_raw(args_raw);
150
151 var
153 }
154}
155impl PtrMagic for pxs_FactoryHolder {}
173
174#[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 pub fn new() -> Self {
212 pxs_VarList { vars: vec![] }
213 }
214
215 pub fn add_item(&mut self, item: pxs_Var) {
217 self.vars.push(item);
218 }
219
220 pub fn get_item(&self, index: i32) -> Option<&pxs_Var> {
222 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 pub fn set_item(&mut self, item: pxs_Var, index: i32) -> bool {
242 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#[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
284pub unsafe extern "C" fn default_deleter(_ptr: *mut c_void) {
287 }
289
290#[repr(C)]
317#[allow(non_camel_case_types)]
318pub struct pxs_Var {
319 pub tag: pxs_VarType,
321 pub value: pxs_VarValue,
323
324 pub deleter: Cell<pxs_DeleterFn>,
326}
327
328impl 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 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 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 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 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 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 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 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 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 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 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 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 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 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 pub unsafe fn from_argv(argc: usize, argv: *mut *mut pxs_Var) -> Vec<pxs_Var> {
508 let argv_borrow = unsafe { pxs_Var::slice_raw(argv, argc) };
510 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 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 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 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 if self.tag == pxs_VarType::pxs_String {
598 unsafe {
599 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 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 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 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 og_list_val = pxs_VarList::from_borrow(self.value.list_val);
682
683 for item in og_list_val.vars.iter() {
685 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 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
752pub trait ObjectMethods {
754 fn object_call(var: &pxs_Var, method: &str, args: &mut pxs_VarList) -> Result<pxs_Var, Error>;
756
757 fn call_method(method: &str, args: &mut pxs_VarList) -> Result<pxs_Var, Error>;
759
760 fn var_call(method: &pxs_Var, args: &mut pxs_VarList) -> Result<pxs_Var, Error>;
762
763 fn get(var: &pxs_Var, key: &str) -> Result<pxs_Var, Error>;
765
766 fn set(var: &pxs_Var, key: &str, value: &pxs_Var) -> Result<pxs_Var, Error>;
768}
769
770#[allow(non_camel_case_types)]
773pub type pxs_VarT = *mut pxs_Var;