1use std::{
64 collections::VecDeque,
65 fmt::{Debug, Display},
66 ptr::addr_eq,
67 sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
68};
69
70use crate::{
71 lambda::runnable::RuntimeError,
72 types::lambda::{
73 native::{
74 native_bool_converter, native_bytes_converter, native_elements_method,
75 native_float_converter, native_int_converter, native_length_method,
76 native_string_converter, wrap_native_function,
77 },
78 parameter::LambdaParameter,
79 },
80 utils::fastmap::{OnionFastMap, OnionKeyPool},
81};
82use arc_gc::{
83 arc::{GCArc, GCArcWeak},
84 gc::GC,
85 traceable::GCTraceable,
86};
87use base64::{Engine as _, engine::general_purpose};
88
89use super::{
90 lambda::{
91 definition::OnionLambdaDefinition, vm_instructions::instruction_set::VMInstructionPackage,
92 },
93 lazy_set::OnionLazySet,
94 pair::OnionPair,
95 tuple::OnionTuple,
96};
97
98pub struct OnionObjectCell(pub RwLock<OnionObject>);
113
114impl OnionObjectCell {
115 #[inline(always)]
130 pub fn with_data<T, F>(&self, f: F) -> Result<T, RuntimeError>
133 where
134 F: FnOnce(&OnionObject) -> Result<T, RuntimeError>,
135 {
136 match self.0.read() {
137 Ok(guard) => match &*guard {
138 OnionObject::Mut(_) => {
139 panic!(
140 "CRITICAL: OnionObjectCell contains Mut object. This indicates a bug in VM object allocation or GC logic. Check mutablize() and object creation paths."
141 )
142 }
143 obj => f(obj),
144 },
145 Err(_) => Err(RuntimeError::BorrowError(
146 "Failed to borrow OnionObjectCell at 'with_data'"
147 .to_string()
148 .into(),
149 )),
150 }
151 }
152
153 #[inline(always)]
168 pub fn with_data_mut<T, F>(&self, f: F) -> Result<T, RuntimeError>
171 where
172 F: FnOnce(&mut OnionObject) -> Result<T, RuntimeError>,
173 {
174 match self.0.write() {
175 Ok(mut guard) => match &mut *guard {
176 OnionObject::Mut(_) => {
177 panic!(
178 "CRITICAL: OnionObjectCell contains Mut object. This indicates a bug in VM object allocation or GC logic. Check mutablize() and object creation paths."
179 )
180 }
181 obj => f(obj),
182 },
183 Err(_) => Err(RuntimeError::BorrowError(
184 "Failed to borrow OnionObjectCell at 'with_data_mut'"
185 .to_string()
186 .into(),
187 )),
188 }
189 }
190
191 #[inline(always)]
199 pub fn with_attribute<T, F>(&self, key: &OnionObject, f: &F) -> Result<T, RuntimeError>
200 where
201 F: Fn(&OnionObject) -> Result<T, RuntimeError>,
202 {
203 self.0
204 .read()
205 .map_err(|_| {
206 RuntimeError::BorrowError(
207 "Failed to borrow OnionObjectCell at 'with_attribute'"
208 .to_string()
209 .into(),
210 )
211 })?
212 .with_attribute(key, f)
213 }
214
215 #[inline(always)]
219 pub fn upgrade(&self, collected: &mut Vec<GCArc<OnionObjectCell>>) {
220 match self.0.read() {
221 Ok(obj) => obj.upgrade(collected),
222 Err(_) => {
223 }
226 }
227 }
228
229 #[inline(always)]
234 pub fn stabilize(self) -> OnionStaticObject {
235 OnionStaticObject::new(self.try_borrow().unwrap().clone())
236 }
237
238 #[inline(always)]
239 pub fn equals(&self, other: &Self) -> Result<bool, RuntimeError> {
240 self.with_data(|obj| other.with_data(|other_obj| obj.equals(other_obj)))
241 }
242
243 #[inline(always)]
244 pub fn repr(&self, ptrs: &Vec<*const OnionObject>) -> Result<String, RuntimeError> {
245 self.with_data(|obj| obj.repr(ptrs))
246 }
247
248 #[inline(always)]
249 pub fn try_borrow(&self) -> Result<RwLockReadGuard<OnionObject>, RuntimeError> {
250 self.0.read().map_err(|_| {
251 RuntimeError::BorrowError(
252 "Failed to borrow OnionObjectCell at 'try_borrow'"
253 .to_string()
254 .into(),
255 )
256 })
257 }
258 #[inline(always)]
259 pub fn try_borrow_mut(&self) -> Result<RwLockWriteGuard<OnionObject>, RuntimeError> {
260 self.0.write().map_err(|_| {
261 RuntimeError::BorrowError(
262 "Failed to borrow OnionObjectCell at 'try_borrow_mut'"
263 .to_string()
264 .into(),
265 )
266 })
267 }
268}
269
270impl std::ops::Deref for OnionObjectCell {
271 type Target = RwLock<OnionObject>;
272
273 fn deref(&self) -> &Self::Target {
274 &self.0
275 }
276}
277
278impl std::ops::DerefMut for OnionObjectCell {
279 fn deref_mut(&mut self) -> &mut Self::Target {
280 &mut self.0
281 }
282}
283
284impl From<RwLock<OnionObject>> for OnionObjectCell {
285 fn from(cell: RwLock<OnionObject>) -> Self {
286 OnionObjectCell(cell)
287 }
288}
289
290impl From<OnionObject> for OnionObjectCell {
291 fn from(obj: OnionObject) -> Self {
292 OnionObjectCell(RwLock::new(obj))
293 }
294}
295
296impl GCTraceable<OnionObjectCell> for OnionObjectCell {
297 fn collect(&self, queue: &mut VecDeque<GCArcWeak<OnionObjectCell>>) {
298 if let Ok(obj) = self.0.read() {
299 obj.collect(queue);
300 }
301 }
302}
303
304impl Debug for OnionObjectCell {
305 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
306 write!(f, "{:?}", self.0.read())
307 }
308}
309
310impl Display for OnionObjectCell {
311 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
312 write!(f, "{:?}", self.0.read())
313 }
314}
315
316#[derive(Clone)]
317pub enum OnionObject {
357 Integer(i64),
364 Float(f64),
365 String(Arc<str>),
366 Bytes(Arc<[u8]>),
367 Boolean(bool),
368 Range(i64, i64),
369 Null,
370 Undefined(Option<Arc<str>>),
371 InstructionPackage(Arc<VMInstructionPackage>),
372
373 Tuple(OnionTuple), Pair(Arc<OnionPair>),
376 LazySet(Arc<OnionLazySet>),
377 Lambda((Arc<OnionLambdaDefinition>, Arc<OnionObject>)), Custom(Arc<dyn OnionObjectExt>),
379
380 Mut(GCArcWeak<OnionObjectCell>),
383}
384
385pub trait OnionObjectExt: GCTraceable<OnionObjectCell> + Debug + Send + Sync + 'static {
438 fn as_any(&self) -> &dyn std::any::Any;
440
441 fn upgrade(&self, collected: &mut Vec<GCArc<OnionObjectCell>>);
443
444 fn to_integer(&self) -> Result<i64, RuntimeError> {
446 Err(RuntimeError::InvalidType(
447 format!("Cannot convert {:?} to Integer", self).into(),
448 ))
449 }
450 fn to_float(&self) -> Result<f64, RuntimeError> {
451 Err(RuntimeError::InvalidType(
452 format!("Cannot convert {:?} to Float", self).into(),
453 ))
454 }
455 #[allow(unused_variables)]
456 fn to_string(&self, ptrs: &Vec<*const OnionObject>) -> Result<String, RuntimeError> {
457 Err(RuntimeError::InvalidType(
458 format!("Cannot convert {:?} to String", self).into(),
459 ))
460 }
461 fn to_bytes(&self) -> Result<Box<[u8]>, RuntimeError> {
462 Err(RuntimeError::InvalidType(
463 format!("Cannot convert {:?} to Bytes", self).into(),
464 ))
465 }
466 fn to_boolean(&self) -> Result<bool, RuntimeError> {
467 Err(RuntimeError::InvalidType(
468 format!("Cannot convert {:?} to Boolean", self).into(),
469 ))
470 }
471 #[allow(unused_variables)]
472 fn repr(&self, ptrs: &Vec<*const OnionObject>) -> Result<String, RuntimeError> {
473 Ok(format!("{:?}", self))
474 }
475 fn type_of(&self) -> Result<String, RuntimeError> {
476 Err(RuntimeError::InvalidType(
477 format!("Cannot get type of {:?}", self).into(),
478 ))
479 }
480
481 fn len(&self) -> Result<OnionStaticObject, RuntimeError> {
483 Err(RuntimeError::InvalidOperation(
484 format!("len() not supported for {:?}", self).into(),
485 ))
486 }
487 fn contains(&self, other: &OnionObject) -> Result<bool, RuntimeError> {
488 Err(RuntimeError::InvalidOperation(
489 format!("contains() not supported for {:?} and {:?}", self, other).into(),
490 ))
491 }
492 fn apply(&self, value: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
493 Err(RuntimeError::InvalidOperation(
494 format!(
495 "apply() not supported for {:?} with value {:?}",
496 self, value
497 )
498 .into(),
499 ))
500 }
501
502 fn key_of(&self) -> Result<OnionStaticObject, RuntimeError> {
504 Err(RuntimeError::InvalidOperation(
505 format!("key_of() not supported for {:?}", self).into(),
506 ))
507 }
508 fn value_of(&self) -> Result<OnionStaticObject, RuntimeError> {
509 Err(RuntimeError::InvalidOperation(
510 format!("value_of() not supported for {:?}", self).into(),
511 ))
512 }
513 #[allow(unused_variables)]
514 fn with_attribute(
515 &self,
516 key: &OnionObject,
517 f: &mut dyn FnMut(&OnionObject) -> Result<(), RuntimeError>,
518 ) -> Result<(), RuntimeError> {
519 Err(RuntimeError::InvalidOperation(
520 format!(
521 "with_attribute() not supported for {:?} with key {:?}",
522 self, key
523 )
524 .into(),
525 ))
526 }
527
528 fn equals(&self, other: &OnionObject) -> Result<bool, RuntimeError>;
530 fn binary_eq(&self, other: &OnionObject) -> Result<bool, RuntimeError> {
531 Err(RuntimeError::InvalidOperation(
532 format!("binary_eq() not supported for {:?} and {:?}", self, other).into(),
533 ))
534 }
535 fn binary_lt(&self, other: &OnionObject) -> Result<bool, RuntimeError> {
536 Err(RuntimeError::InvalidOperation(
537 format!("binary_lt() not supported for {:?} and {:?}", self, other).into(),
538 ))
539 }
540 fn binary_gt(&self, other: &OnionObject) -> Result<bool, RuntimeError> {
541 Err(RuntimeError::InvalidOperation(
542 format!("binary_gt() not supported for {:?} and {:?}", self, other).into(),
543 ))
544 }
545
546 fn binary_add(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
548 Err(RuntimeError::InvalidOperation(
549 format!("binary_add() not supported for {:?} and {:?}", self, other).into(),
550 ))
551 }
552 fn binary_sub(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
553 Err(RuntimeError::InvalidOperation(
554 format!("binary_sub() not supported for {:?} and {:?}", self, other).into(),
555 ))
556 }
557 fn binary_mul(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
558 Err(RuntimeError::InvalidOperation(
559 format!("binary_mul() not supported for {:?} and {:?}", self, other).into(),
560 ))
561 }
562 fn binary_div(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
563 Err(RuntimeError::InvalidOperation(
564 format!("binary_div() not supported for {:?} and {:?}", self, other).into(),
565 ))
566 }
567 fn binary_mod(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
568 Err(RuntimeError::InvalidOperation(
569 format!("binary_mod() not supported for {:?} and {:?}", self, other).into(),
570 ))
571 }
572 fn binary_pow(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
573 Err(RuntimeError::InvalidOperation(
574 format!("binary_pow() not supported for {:?} and {:?}", self, other).into(),
575 ))
576 }
577
578 fn binary_and(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
580 Err(RuntimeError::InvalidOperation(
581 format!("binary_and() not supported for {:?} and {:?}", self, other).into(),
582 ))
583 }
584 fn binary_or(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
585 Err(RuntimeError::InvalidOperation(
586 format!("binary_or() not supported for {:?} and {:?}", self, other).into(),
587 ))
588 }
589 fn binary_xor(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
590 Err(RuntimeError::InvalidOperation(
591 format!("binary_xor() not supported for {:?} and {:?}", self, other).into(),
592 ))
593 }
594
595 fn binary_shl(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
597 Err(RuntimeError::InvalidOperation(
598 format!("binary_shl() not supported for {:?} and {:?}", self, other).into(),
599 ))
600 }
601 fn binary_shr(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
602 Err(RuntimeError::InvalidOperation(
603 format!("binary_shr() not supported for {:?} and {:?}", self, other).into(),
604 ))
605 }
606
607 fn unary_neg(&self) -> Result<OnionStaticObject, RuntimeError> {
609 Err(RuntimeError::InvalidOperation(
610 format!("unary_neg() not supported for {:?}", self).into(),
611 ))
612 }
613 fn unary_plus(&self) -> Result<OnionStaticObject, RuntimeError> {
614 Err(RuntimeError::InvalidOperation(
615 format!("unary_plus() not supported for {:?}", self).into(),
616 ))
617 }
618 fn unary_not(&self) -> Result<OnionStaticObject, RuntimeError> {
619 Err(RuntimeError::InvalidOperation(
620 format!("unary_not() not supported for {:?}", self).into(),
621 ))
622 }
623}
624
625impl Debug for OnionObject {
626 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
627 write!(
629 f,
630 "{}",
631 self.repr(&vec![])
632 .unwrap_or_else(|_| "BrokenReference".to_string())
633 )
634 }
635}
636
637impl GCTraceable<OnionObjectCell> for OnionObject {
638 fn collect(&self, queue: &mut VecDeque<GCArcWeak<OnionObjectCell>>) {
639 match self {
640 OnionObject::Mut(weak) => {
641 queue.push_back(weak.clone());
642 }
643 OnionObject::Tuple(tuple) => tuple.collect(queue),
644 OnionObject::Pair(pair) => pair.collect(queue),
645 OnionObject::LazySet(lazy_set) => lazy_set.collect(queue),
646 OnionObject::Lambda(lambda) => {
647 lambda.0.collect(queue);
648 lambda.1.collect(queue);
649 }
650 OnionObject::Custom(custom) => custom.collect(queue),
651
652 _ => {}
653 }
654 }
655}
656impl OnionObject {
657 pub fn upgrade(&self, collected: &mut Vec<GCArc<OnionObjectCell>>) {
664 match self {
665 OnionObject::Mut(weak) => {
666 if let Some(strong) = weak.upgrade() {
667 collected.push(strong);
668 }
669 }
670 OnionObject::Tuple(tuple) => tuple.upgrade(collected),
671 OnionObject::Pair(pair) => pair.upgrade(collected),
672 OnionObject::LazySet(lazy_set) => lazy_set.upgrade(collected),
673 OnionObject::Lambda(lambda) => {
674 lambda.0.upgrade(collected);
675 lambda.1.upgrade(collected);
676 }
677 OnionObject::Custom(custom) => custom.upgrade(collected),
678 _ => {}
679 }
680 }
681
682 #[inline(always)]
686 pub fn to_cell(self) -> OnionObjectCell {
687 OnionObjectCell(RwLock::new(self))
688 }
689
690 #[inline(always)]
694 pub fn stabilize(&self) -> OnionStaticObject {
695 OnionStaticObject::new(self.clone())
696 }
697
698 #[inline(always)]
702 pub fn consume_and_stabilize(self) -> OnionStaticObject {
703 OnionStaticObject::new(self)
704 }
705
706 #[inline(always)]
713 pub fn with_data<T, F>(&self, f: F) -> Result<T, RuntimeError>
714 where
715 F: FnOnce(&OnionObject) -> Result<T, RuntimeError>,
716 {
717 match self {
718 OnionObject::Mut(weak) => {
719 if let Some(strong) = weak.upgrade() {
720 strong.as_ref().with_data(f)
721 } else {
722 Err(RuntimeError::BrokenReference)
723 }
724 }
725 _ => f(self),
726 }
727 }
728
729 #[inline(always)]
736 pub fn with_data_mut<T, F>(&mut self, f: F) -> Result<T, RuntimeError>
737 where
738 F: FnOnce(&mut OnionObject) -> Result<T, RuntimeError>,
739 {
740 match self {
741 OnionObject::Mut(weak) => {
742 if let Some(strong) = weak.upgrade() {
743 strong.as_ref().with_data_mut(f)
744 } else {
745 Err(RuntimeError::BrokenReference)
746 }
747 }
748 _ => f(self),
749 }
750 }
751
752 #[inline(always)]
767 pub fn assign(&self, other: &OnionObject) -> Result<(), RuntimeError> {
769 let OnionObject::Mut(weak) = self else {
772 return Err(RuntimeError::InvalidOperation(
773 format!("Cannot assign to immutable object: {:?}", self).into(),
774 ));
775 };
776 match weak.upgrade() {
777 Some(strong) => {
778 let new_value = other.with_data(|other| Ok(other.clone()))?;
780
781 strong.as_ref().with_data_mut(|obj| {
783 *obj = new_value;
784 Ok(())
785 })
786 }
787 None => Err(RuntimeError::BrokenReference),
788 }
789 }
790
791 #[inline(always)]
806 fn mutablize(self, gc: &mut GC<OnionObjectCell>) -> OnionStaticObject {
807 let arc = gc.create(OnionObjectCell::from(self));
808 OnionStaticObject {
809 obj: OnionObject::Mut(arc.as_weak()),
810 _arcs: GCArcStorage::Single(arc),
811 }
812 }
813}
814
815impl OnionObject {
820 pub fn equals(&self, other: &Self) -> Result<bool, RuntimeError> {
836 self.with_data(|left| {
837 other.with_data(|right| {
838 match (left, right) {
839 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => Ok(i1 == i2),
840 (OnionObject::Float(f1), OnionObject::Float(f2)) => Ok(f1 == f2),
841 (OnionObject::Integer(i1), OnionObject::Float(f2)) => Ok(*i1 as f64 == *f2),
842 (OnionObject::Float(f1), OnionObject::Integer(i2)) => Ok(*f1 == *i2 as f64),
843 (OnionObject::String(s1), OnionObject::String(s2)) => Ok(s1 == s2),
844 (OnionObject::Bytes(b1), OnionObject::Bytes(b2)) => Ok(b1 == b2),
845 (OnionObject::Boolean(b1), OnionObject::Boolean(b2)) => Ok(b1 == b2),
846 (OnionObject::Range(start1, end1), OnionObject::Range(start2, end2)) => {
847 Ok(start1 == start2 && end1 == end2)
848 }
849 (OnionObject::Null, OnionObject::Null) => Ok(true),
850 (OnionObject::Undefined(_), OnionObject::Undefined(_)) => Ok(true),
851 (OnionObject::Tuple(t1), _) => t1.equals(other),
852 (OnionObject::Pair(p1), _) => p1.equals(other),
853 (OnionObject::Custom(c1), _) => c1.equals(other),
854
855 _ => Ok(false),
857 }
858 })
859 })
860 }
861
862 pub fn is_same(&self, other: &Self) -> Result<bool, RuntimeError> {
866 match (self, other) {
867 (OnionObject::Mut(weak1), OnionObject::Mut(weak2)) => {
868 if let (Some(strong1), Some(strong2)) = (weak1.upgrade(), weak2.upgrade()) {
869 Ok(addr_eq(strong1.as_ref(), strong2.as_ref()))
870 } else {
871 Ok(false)
872 }
873 }
874 _ => Ok(false), }
876 }
877
878 pub fn len(&self) -> Result<OnionStaticObject, RuntimeError> {
889 self.with_data(|obj| match obj {
890 OnionObject::Tuple(tuple) => tuple.len(),
891 OnionObject::String(s) => {
892 Ok(OnionStaticObject::new(OnionObject::Integer(s.len() as i64)))
893 }
894 OnionObject::Bytes(b) => {
895 Ok(OnionStaticObject::new(OnionObject::Integer(b.len() as i64)))
896 }
897 OnionObject::Range(start, end) => Ok(OnionStaticObject::new(OnionObject::Integer(
898 (end - start) as i64,
899 ))),
900 OnionObject::Custom(custom) => custom.len(),
901 _ => Err(RuntimeError::InvalidOperation(
902 format!("len() not supported for {:?}", self).into(),
903 )),
904 })
905 }
906
907 pub fn contains(&self, other: &OnionObject) -> Result<bool, RuntimeError> {
908 self.with_data(|obj| {
909 other.with_data(|other_obj| match (obj, other_obj) {
910 (OnionObject::Tuple(tuple), _) => tuple.contains(other_obj),
911 (OnionObject::String(s), OnionObject::String(other_s)) => {
912 Ok(s.contains(other_s.as_ref()))
913 }
914 (OnionObject::Bytes(b), OnionObject::Bytes(other_b)) => Ok(b
915 .windows(other_b.len())
916 .any(|window| window.eq(other_b.as_ref()))),
917 (OnionObject::Range(l, r), OnionObject::Integer(i)) => Ok(*i >= *l && *i < *r),
918 (OnionObject::Range(start, end), OnionObject::Float(f)) => {
919 Ok(*f >= *start as f64 && *f < *end as f64)
920 }
921 (OnionObject::Range(start, end), OnionObject::Range(other_start, other_end)) => {
922 Ok(*other_start >= *start && *other_end <= *end)
923 }
924 (OnionObject::Custom(custom), _) => custom.contains(other_obj),
925 _ => Err(RuntimeError::InvalidOperation(
926 format!("contains() not supported for {:?}", obj).into(),
927 )),
928 })
929 })
930 }
931
932 pub fn to_integer(&self) -> Result<i64, RuntimeError> {
947 self.with_data(|obj| match obj {
948 OnionObject::Integer(i) => Ok(*i),
949 OnionObject::Float(f) => Ok(*f as i64),
950 OnionObject::String(s) => s
951 .parse::<i64>()
952 .map_err(|e| RuntimeError::InvalidType(e.to_string().into())),
953 OnionObject::Boolean(b) => Ok(if *b { 1 } else { 0 }),
954 OnionObject::Custom(custom) => custom.to_integer(),
955 _ => Err(RuntimeError::InvalidType(
956 format!("Cannot convert {:?} to Integer", obj).into(),
957 )),
958 })
959 }
960 pub fn to_float(&self) -> Result<f64, RuntimeError> {
961 self.with_data(|obj| match obj {
962 OnionObject::Integer(i) => Ok(*i as f64),
963 OnionObject::Float(f) => Ok(*f),
964 OnionObject::String(s) => s
965 .parse::<f64>()
966 .map_err(|e| RuntimeError::InvalidType(e.to_string().into())),
967 OnionObject::Boolean(b) => Ok(if *b { 1.0 } else { 0.0 }),
968 OnionObject::Custom(custom) => custom.to_float(),
969 _ => Err(RuntimeError::InvalidType(
970 format!("Cannot convert {:?} to Float", obj).into(),
971 )),
972 })
973 }
974
975 pub fn to_string(&self, ptrs: &Vec<*const OnionObject>) -> Result<String, RuntimeError> {
976 self.with_data(|obj| {
977 for ptr in ptrs {
978 if addr_eq(obj, *ptr) {
979 return Ok("...".to_string());
980 }
981 }
982 let mut new_ptrs = ptrs.clone();
983 new_ptrs.push(obj);
984 match obj {
985 OnionObject::Integer(i) => Ok(i.to_string()),
986 OnionObject::Float(f) => Ok(f.to_string()),
987 OnionObject::String(s) => Ok(s.to_string()),
988 OnionObject::Bytes(b) => Ok(format!(
989 "$\"{}\"",
990 general_purpose::STANDARD.encode(b.as_ref())
991 )),
992 OnionObject::Boolean(b) => Ok(if *b {
993 "true".to_string()
994 } else {
995 "false".to_string()
996 }),
997 OnionObject::Null => Ok("null".to_string()),
998 OnionObject::Undefined(s) => Ok(match s {
999 Some(s) => format!("undefined({:?})", s),
1000 None => "undefined".to_string(),
1001 }),
1002 OnionObject::Range(start, end) => Ok(format!("{}..{}", start, end)),
1003 OnionObject::Tuple(tuple) => match tuple.get_elements().len() {
1004 0 => Ok("()".to_string()),
1005 1 => {
1006 let first = tuple.get_elements().first().unwrap();
1007 Ok(format!("({},)", first.repr(&new_ptrs)?))
1008 }
1009 _ => {
1010 let elements: Result<Vec<String>, RuntimeError> = tuple
1011 .get_elements()
1012 .iter()
1013 .map(|e| e.repr(&new_ptrs))
1014 .collect();
1015 Ok(format!("({})", elements?.join(", ")))
1016 }
1017 },
1018 OnionObject::Pair(pair) => {
1019 let left = pair.get_key().repr(&new_ptrs)?;
1020 let right = pair.get_value().repr(&new_ptrs)?;
1021 Ok(format!("{} : {}", left, right))
1022 }
1023 OnionObject::LazySet(lazy_set) => {
1024 let container = lazy_set.get_container().repr(&new_ptrs)?;
1025 let filter = lazy_set.get_filter().repr(&new_ptrs)?;
1026 Ok(format!("[{} | {}]", container, filter))
1027 }
1028 OnionObject::InstructionPackage(_) => Ok("InstructionPackage(...)".to_string()),
1029 OnionObject::Lambda(lambda) => {
1030 let body = lambda.0.get_body().to_string();
1031 Ok(format!(
1032 "{}::{} -> {}",
1033 lambda.0.get_signature(),
1034 lambda.0.get_parameter(),
1035 body
1036 ))
1037 }
1038 OnionObject::Custom(custom) => custom.to_string(&new_ptrs),
1039 _ => {
1040 Ok(format!("{:?}", obj))
1042 }
1043 }
1044 })
1045 }
1046
1047 pub fn repr(&self, ptrs: &Vec<*const OnionObject>) -> Result<String, RuntimeError> {
1048 self.with_data(|obj| {
1049 for ptr in ptrs {
1050 if addr_eq(obj, *ptr) {
1051 return Ok("...".to_string());
1052 }
1053 }
1054 let mut new_ptrs = ptrs.clone();
1055 new_ptrs.push(obj);
1056 match obj {
1057 OnionObject::Integer(i) => Ok(format!("{}", i)),
1058 OnionObject::Float(f) => Ok(format!("{}", f)),
1059 OnionObject::String(s) => Ok(format!("{:?}", s)),
1060 OnionObject::Bytes(b) => Ok(format!(
1061 "$\"{}\"",
1062 general_purpose::STANDARD.encode(b.as_ref())
1063 )),
1064 OnionObject::Boolean(b) => Ok(format!("{}", b)),
1065 OnionObject::Null => Ok("null".to_string()),
1066 OnionObject::Undefined(s) => Ok(match s {
1067 Some(s) => format!("undefined({:?})", s),
1068 None => "undefined".to_string(),
1069 }),
1070 OnionObject::Range(start, end) => Ok(format!("{}..{}", start, end)),
1071 OnionObject::Tuple(tuple) => match tuple.get_elements().len() {
1072 0 => Ok("()".to_string()),
1073 1 => {
1074 let first = tuple.get_elements().first().unwrap();
1075 Ok(format!("({},)", first.repr(&new_ptrs)?))
1076 }
1077 _ => {
1078 let elements: Result<Vec<String>, RuntimeError> = tuple
1079 .get_elements()
1080 .iter()
1081 .map(|e| e.repr(&new_ptrs))
1082 .collect();
1083 Ok(format!("({})", elements?.join(", ")))
1084 }
1085 },
1086 OnionObject::Pair(pair) => {
1087 let left = pair.get_key().repr(&new_ptrs)?;
1088 let right = pair.get_value().repr(&new_ptrs)?;
1089 Ok(format!("{} : {}", left, right))
1090 }
1091 OnionObject::LazySet(lazy_set) => {
1092 let container = lazy_set.get_container().repr(&new_ptrs)?;
1093 let filter = lazy_set.get_filter().repr(&new_ptrs)?;
1094 Ok(format!("[{} | {}]", container, filter))
1095 }
1096 OnionObject::InstructionPackage(_) => Ok("InstructionPackage(...)".to_string()),
1097 OnionObject::Lambda(lambda) => Ok(format!(
1098 "{}::{} -> {}",
1099 lambda.0.get_signature(),
1100 lambda.0.get_parameter(),
1101 lambda.0.get_body()
1102 )),
1103 OnionObject::Mut(weak) => {
1104 if let Some(strong) = weak.upgrade() {
1105 let inner_repr = strong
1106 .as_ref()
1107 .try_borrow()
1108 .map_err(|_| {
1109 RuntimeError::BorrowError(
1110 "Failed to borrow Mut object at 'repr'".into(),
1111 )
1112 })?
1113 .repr(&new_ptrs)?;
1114 Ok(format!("mut ({})", inner_repr))
1115 } else {
1116 Ok("Mut(BrokenReference)".to_string())
1117 }
1118 }
1119 OnionObject::Custom(custom) => {
1120 let custom_repr = custom.repr(&new_ptrs)?;
1121 Ok(format!("Custom({})", custom_repr))
1122 }
1123 }
1124 })
1125 }
1126 pub fn to_bytes(&self) -> Result<Box<[u8]>, RuntimeError> {
1127 self.with_data(|obj| match obj {
1128 OnionObject::Integer(i) => Ok(i.to_string().into_bytes().into_boxed_slice()),
1129 OnionObject::Float(f) => Ok(f.to_string().into_bytes().into_boxed_slice()),
1130 OnionObject::String(s) => Ok(s.as_bytes().to_vec().into_boxed_slice()),
1131 OnionObject::Bytes(b) => Ok(b.as_ref().to_vec().into_boxed_slice()),
1132 OnionObject::Boolean(b) => Ok(if *b {
1133 b"true".to_vec().into_boxed_slice()
1134 } else {
1135 b"false".to_vec().into_boxed_slice()
1136 }),
1137 OnionObject::Custom(custom) => custom.to_bytes(),
1138 _ => Err(RuntimeError::InvalidType(
1139 format!("Cannot convert {:?} to Bytes", obj).into(),
1140 )),
1141 })
1142 }
1143
1144 pub fn to_boolean(&self) -> Result<bool, RuntimeError> {
1145 self.with_data(|obj| match obj {
1146 OnionObject::Integer(i) => Ok(*i != 0),
1147 OnionObject::Float(f) => Ok(*f != 0.0),
1148 OnionObject::String(s) => Ok(!s.is_empty()),
1149 OnionObject::Bytes(b) => Ok(!b.is_empty()),
1150 OnionObject::Boolean(b) => Ok(*b),
1151 OnionObject::Null => Ok(false),
1152 OnionObject::Undefined(_) => Ok(false),
1153 OnionObject::Custom(custom) => custom.to_boolean(),
1154 _ => Err(RuntimeError::InvalidType(
1155 format!("Cannot convert {:?} to Boolean", obj).into(),
1156 )),
1157 })
1158 }
1159
1160 pub fn binary_add(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
1161 self.with_data(|obj| {
1162 other.with_data(|other_obj| match (obj, other_obj) {
1163 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => {
1164 Ok(OnionStaticObject::new(OnionObject::Integer(i1 + i2)))
1165 }
1166 (OnionObject::Float(f1), OnionObject::Float(f2)) => {
1167 Ok(OnionStaticObject::new(OnionObject::Float(f1 + f2)))
1168 }
1169 (OnionObject::Integer(i1), OnionObject::Float(f2)) => {
1170 Ok(OnionStaticObject::new(OnionObject::Float(*i1 as f64 + f2)))
1171 }
1172 (OnionObject::Float(f1), OnionObject::Integer(i2)) => {
1173 Ok(OnionStaticObject::new(OnionObject::Float(f1 + *i2 as f64)))
1174 }
1175 (OnionObject::String(s1), OnionObject::String(s2)) => Ok(OnionStaticObject::new(
1176 OnionObject::String(Arc::from(format!("{}{}", s1, s2))),
1177 )),
1178 (OnionObject::Bytes(b1), OnionObject::Bytes(b2)) => {
1179 let mut new_bytes = Vec::with_capacity(b1.len() + b2.len());
1180 new_bytes.extend_from_slice(b1.as_ref());
1181 new_bytes.extend_from_slice(b2.as_ref());
1182 Ok(OnionStaticObject::new(OnionObject::Bytes(Arc::from(
1183 new_bytes,
1184 ))))
1185 }
1186 (OnionObject::Range(start1, end1), OnionObject::Range(start2, end2)) => Ok(
1187 OnionStaticObject::new(OnionObject::Range(start1 + start2, end1 + end2)),
1188 ),
1189 (OnionObject::Tuple(t1), _) => t1.binary_add(other_obj),
1190 (OnionObject::Custom(c1), _) => c1.binary_add(other_obj),
1191 _ => Err(RuntimeError::InvalidOperation(
1192 format!(
1193 "Invalid binary add operation for {:?} and {:?}",
1194 obj, other_obj
1195 )
1196 .into(),
1197 )),
1198 })
1199 })
1200 }
1201
1202 pub fn binary_sub(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
1203 self.with_data(|obj| {
1204 other.with_data(|other_obj| match (obj, other_obj) {
1205 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => {
1206 Ok(OnionStaticObject::new(OnionObject::Integer(i1 - i2)))
1207 }
1208 (OnionObject::Float(f1), OnionObject::Float(f2)) => {
1209 Ok(OnionStaticObject::new(OnionObject::Float(f1 - f2)))
1210 }
1211 (OnionObject::Integer(i1), OnionObject::Float(f2)) => {
1212 Ok(OnionStaticObject::new(OnionObject::Float(*i1 as f64 - f2)))
1213 }
1214 (OnionObject::Float(f1), OnionObject::Integer(i2)) => {
1215 Ok(OnionStaticObject::new(OnionObject::Float(f1 - *i2 as f64)))
1216 }
1217 (OnionObject::Custom(c1), _) => c1.binary_sub(other_obj),
1218 _ => Err(RuntimeError::InvalidOperation(
1219 format!(
1220 "Invalid binary sub operation for {:?} and {:?}",
1221 obj, other_obj
1222 )
1223 .into(),
1224 )),
1225 })
1226 })
1227 }
1228
1229 pub fn binary_mul(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
1230 self.with_data(|obj| {
1231 other.with_data(|other_obj| match (obj, other_obj) {
1232 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => {
1233 Ok(OnionStaticObject::new(OnionObject::Integer(i1 * i2)))
1234 }
1235 (OnionObject::Float(f1), OnionObject::Float(f2)) => {
1236 Ok(OnionStaticObject::new(OnionObject::Float(f1 * f2)))
1237 }
1238 (OnionObject::Integer(i1), OnionObject::Float(f2)) => {
1239 Ok(OnionStaticObject::new(OnionObject::Float(*i1 as f64 * f2)))
1240 }
1241 (OnionObject::Float(f1), OnionObject::Integer(i2)) => {
1242 Ok(OnionStaticObject::new(OnionObject::Float(f1 * *i2 as f64)))
1243 }
1244 (OnionObject::Custom(c1), _) => c1.binary_mul(other_obj),
1245 _ => Err(RuntimeError::InvalidOperation(
1246 format!(
1247 "Invalid binary mul operation for {:?} and {:?}",
1248 obj, other_obj
1249 )
1250 .into(),
1251 )),
1252 })
1253 })
1254 }
1255
1256 pub fn binary_div(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
1257 self.with_data(|obj| {
1258 other.with_data(|other_obj| match (obj, other_obj) {
1259 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => {
1260 if *i2 == 0 {
1261 return Err(RuntimeError::InvalidOperation("Division by zero".into()));
1262 }
1263 Ok(OnionStaticObject::new(OnionObject::Integer(i1 / i2)))
1264 }
1265 (OnionObject::Float(f1), OnionObject::Float(f2)) => {
1266 Ok(OnionStaticObject::new(OnionObject::Float(f1 / f2)))
1267 }
1268 (OnionObject::Integer(i1), OnionObject::Float(f2)) => {
1269 Ok(OnionStaticObject::new(OnionObject::Float(*i1 as f64 / f2)))
1270 }
1271 (OnionObject::Float(f1), OnionObject::Integer(i2)) => {
1272 Ok(OnionStaticObject::new(OnionObject::Float(f1 / *i2 as f64)))
1273 }
1274 (OnionObject::Custom(c1), _) => c1.binary_div(other_obj),
1275 _ => Err(RuntimeError::InvalidOperation(
1276 format!(
1277 "Invalid binary div operation for {:?} and {:?}",
1278 obj, other_obj
1279 )
1280 .into(),
1281 )),
1282 })
1283 })
1284 }
1285
1286 pub fn binary_mod(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
1287 self.with_data(|obj| {
1288 other.with_data(|other_obj| match (obj, other_obj) {
1289 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => {
1290 if *i2 == 0 {
1291 return Err(RuntimeError::InvalidOperation("Division by zero".into()));
1292 }
1293 Ok(OnionStaticObject::new(OnionObject::Integer(i1 % i2)))
1294 }
1295 (OnionObject::Float(f1), OnionObject::Float(f2)) => {
1296 Ok(OnionStaticObject::new(OnionObject::Float(f1 % f2)))
1297 }
1298 (OnionObject::Integer(i1), OnionObject::Float(f2)) => {
1299 Ok(OnionStaticObject::new(OnionObject::Float(*i1 as f64 % f2)))
1300 }
1301 (OnionObject::Float(f1), OnionObject::Integer(i2)) => {
1302 Ok(OnionStaticObject::new(OnionObject::Float(f1 % *i2 as f64)))
1303 }
1304 (OnionObject::Custom(c1), _) => c1.binary_mod(other_obj),
1305 _ => Err(RuntimeError::InvalidOperation(
1306 format!(
1307 "Invalid binary mod operation for {:?} and {:?}",
1308 obj, other_obj
1309 )
1310 .into(),
1311 )),
1312 })
1313 })
1314 }
1315
1316 pub fn binary_pow(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
1317 self.with_data(|obj| {
1318 other.with_data(|other_obj| match (obj, other_obj) {
1319 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => Ok(OnionStaticObject::new(
1320 OnionObject::Integer(i1.pow(*i2 as u32)),
1321 )),
1322 (OnionObject::Float(f1), OnionObject::Float(f2)) => {
1323 Ok(OnionStaticObject::new(OnionObject::Float(f1.powf(*f2))))
1324 }
1325 (OnionObject::Integer(i1), OnionObject::Float(f2)) => Ok(OnionStaticObject::new(
1326 OnionObject::Float((*i1 as f64).powf(*f2)),
1327 )),
1328 (OnionObject::Float(f1), OnionObject::Integer(i2)) => Ok(OnionStaticObject::new(
1329 OnionObject::Float(f1.powi(*i2 as i32)),
1330 )),
1331 (OnionObject::Custom(c1), _) => c1.binary_pow(other_obj),
1332 _ => Err(RuntimeError::InvalidOperation(
1333 format!(
1334 "Invalid binary pow operation for {:?} and {:?}",
1335 obj, other_obj
1336 )
1337 .into(),
1338 )),
1339 })
1340 })
1341 }
1342
1343 pub fn binary_and(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
1344 self.with_data(|obj| {
1345 other.with_data(|other_obj| match (obj, other_obj) {
1346 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => {
1347 Ok(OnionStaticObject::new(OnionObject::Integer(i1 & i2)))
1348 }
1349 (OnionObject::Boolean(f1), OnionObject::Boolean(f2)) => {
1350 Ok(OnionStaticObject::new(OnionObject::Boolean(*f1 && *f2)))
1351 }
1352 (OnionObject::Custom(c1), _) => c1.binary_and(other_obj),
1353 _ => Err(RuntimeError::InvalidOperation(
1354 format!(
1355 "Invalid binary and operation for {:?} and {:?}",
1356 obj, other_obj
1357 )
1358 .into(),
1359 )),
1360 })
1361 })
1362 }
1363
1364 pub fn binary_or(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
1365 self.with_data(|obj| {
1366 other.with_data(|other_obj| match (obj, other_obj) {
1367 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => {
1368 Ok(OnionStaticObject::new(OnionObject::Integer(i1 | i2)))
1369 }
1370 (OnionObject::Boolean(f1), OnionObject::Boolean(f2)) => {
1371 Ok(OnionStaticObject::new(OnionObject::Boolean(*f1 || *f2)))
1372 }
1373 (OnionObject::Custom(c1), _) => c1.binary_or(other_obj),
1374 _ => Err(RuntimeError::InvalidOperation(
1375 format!(
1376 "Invalid binary or operation for {:?} and {:?}",
1377 obj, other_obj
1378 )
1379 .into(),
1380 )),
1381 })
1382 })
1383 }
1384
1385 pub fn binary_xor(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
1386 self.with_data(|obj| {
1387 other.with_data(|other_obj| match (obj, other_obj) {
1388 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => {
1389 Ok(OnionStaticObject::new(OnionObject::Integer(i1 ^ i2)))
1390 }
1391 (OnionObject::Custom(c1), _) => c1.binary_xor(other_obj),
1392 _ => Err(RuntimeError::InvalidOperation(
1393 format!(
1394 "Invalid binary xor operation for {:?} and {:?}",
1395 obj, other_obj
1396 )
1397 .into(),
1398 )),
1399 })
1400 })
1401 }
1402
1403 pub fn binary_shl(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
1404 self.with_data(|obj| {
1405 other.with_data(|other_obj| match (obj, other_obj) {
1406 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => {
1407 Ok(OnionStaticObject::new(OnionObject::Integer(i1 << i2)))
1408 }
1409 (OnionObject::Custom(c1), _) => c1.binary_shl(other_obj),
1410 _ => Err(RuntimeError::InvalidOperation(
1411 format!(
1412 "Invalid binary shl operation for {:?} and {:?}",
1413 obj, other_obj
1414 )
1415 .into(),
1416 )),
1417 })
1418 })
1419 }
1420
1421 pub fn binary_shr(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
1422 self.with_data(|obj| {
1423 other.with_data(|other_obj| match (obj, other_obj) {
1424 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => {
1425 Ok(OnionStaticObject::new(OnionObject::Integer(i1 >> i2)))
1426 }
1427 (OnionObject::Custom(c1), _) => c1.binary_shr(other_obj),
1428 _ => Err(RuntimeError::InvalidOperation(
1429 format!(
1430 "Invalid binary shr operation for {:?} and {:?}",
1431 obj, other_obj
1432 )
1433 .into(),
1434 )),
1435 })
1436 })
1437 }
1438
1439 pub fn binary_eq(&self, other: &Self) -> Result<bool, RuntimeError> {
1440 self.equals(other)
1441 }
1442
1443 pub fn binary_lt(&self, other: &Self) -> Result<bool, RuntimeError> {
1444 self.with_data(|obj| {
1445 other.with_data(|other_obj| match (obj, other_obj) {
1446 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => Ok(i1 < i2),
1447 (OnionObject::Float(f1), OnionObject::Float(f2)) => Ok(f1 < f2),
1448 (OnionObject::Integer(i1), OnionObject::Float(f2)) => Ok((*i1 as f64) < *f2),
1449 (OnionObject::Float(f1), OnionObject::Integer(i2)) => Ok(*f1 < *i2 as f64),
1450 (OnionObject::Custom(c1), _) => c1.binary_lt(other_obj),
1451 _ => Err(RuntimeError::InvalidOperation(
1452 format!(
1453 "Invalid binary lt operation for {:?} and {:?}",
1454 obj, other_obj
1455 )
1456 .into(),
1457 )),
1458 })
1459 })
1460 }
1461
1462 pub fn binary_gt(&self, other: &Self) -> Result<bool, RuntimeError> {
1463 self.with_data(|obj| {
1464 other.with_data(|other_obj| match (obj, other_obj) {
1465 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => Ok(i1 > i2),
1466 (OnionObject::Float(f1), OnionObject::Float(f2)) => Ok(f1 > f2),
1467 (OnionObject::Integer(i1), OnionObject::Float(f2)) => Ok((*i1 as f64) > *f2),
1468 (OnionObject::Float(f1), OnionObject::Integer(i2)) => Ok(*f1 > *i2 as f64),
1469 (OnionObject::Custom(c1), _) => c1.binary_gt(other_obj),
1470 _ => Err(RuntimeError::InvalidOperation(
1471 format!(
1472 "Invalid binary gt operation for {:?} and {:?}",
1473 obj, other_obj
1474 )
1475 .into(),
1476 )),
1477 })
1478 })
1479 }
1480
1481 pub fn unary_neg(&self) -> Result<OnionStaticObject, RuntimeError> {
1482 self.with_data(|obj| match obj {
1483 OnionObject::Integer(i) => Ok(OnionStaticObject::new(OnionObject::Integer(-i))),
1484 OnionObject::Float(f) => Ok(OnionStaticObject::new(OnionObject::Float(-f))),
1485 OnionObject::Custom(custom) => custom.unary_neg(),
1486 _ => Err(RuntimeError::InvalidOperation(
1487 format!("Invalid unary neg operation for {:?}", obj).into(),
1488 )),
1489 })
1490 }
1491
1492 pub fn unary_plus(&self) -> Result<OnionStaticObject, RuntimeError> {
1493 self.with_data(|obj| match obj {
1494 OnionObject::Integer(i) => Ok(OnionStaticObject::new(OnionObject::Integer(i.abs()))),
1495 OnionObject::Float(f) => Ok(OnionStaticObject::new(OnionObject::Float(f.abs()))),
1496 OnionObject::Custom(custom) => custom.unary_plus(),
1497 _ => Err(RuntimeError::InvalidOperation(
1498 format!("Invalid unary plus operation for {:?}", obj).into(),
1499 )),
1500 })
1501 }
1502
1503 pub fn unary_not(&self) -> Result<OnionStaticObject, RuntimeError> {
1504 self.with_data(|obj| match obj {
1505 OnionObject::Boolean(b) => Ok(OnionStaticObject::new(OnionObject::Boolean(!b))),
1506 OnionObject::Integer(i) => Ok(OnionStaticObject::new(OnionObject::Integer(!i))),
1507 OnionObject::Custom(custom) => custom.unary_not(),
1508 _ => Err(RuntimeError::InvalidOperation(
1509 format!("Invalid unary not operation for {:?}", obj).into(),
1510 )),
1511 })
1512 }
1513
1514 pub fn with_attribute<F, R>(&self, key: &OnionObject, f: &F) -> Result<R, RuntimeError>
1515 where
1516 F: Fn(&OnionObject) -> Result<R, RuntimeError>,
1517 {
1518 self.with_data(|obj| match obj {
1519 OnionObject::Integer(_) => {
1520 if let OnionObject::String(key_str) = key {
1521 match key_str.as_ref() {
1522 "int" => {
1523 let converter = wrap_native_function(
1524 LambdaParameter::Multiple(Box::new([])),
1525 OnionFastMap::new(OnionKeyPool::create(vec![])),
1526 obj,
1527 "converter::int",
1528 OnionKeyPool::create(vec![]),
1529 &native_int_converter,
1530 );
1531 return f(converter.weak());
1532 }
1533 "float" => {
1534 let converter = wrap_native_function(
1535 LambdaParameter::Multiple(Box::new([])),
1536 OnionFastMap::new(OnionKeyPool::create(vec![])),
1537 obj,
1538 "converter::float",
1539 OnionKeyPool::create(vec![]),
1540 &native_float_converter,
1541 );
1542 return f(converter.weak());
1543 }
1544 "string" => {
1545 let converter = wrap_native_function(
1546 LambdaParameter::Multiple(Box::new([])),
1547 OnionFastMap::new(OnionKeyPool::create(vec![])),
1548 obj,
1549 "converter::string",
1550 OnionKeyPool::create(vec![]),
1551 &native_string_converter,
1552 );
1553 return f(converter.weak());
1554 }
1555 "bool" => {
1556 let converter = wrap_native_function(
1557 LambdaParameter::Multiple(Box::new([])),
1558 OnionFastMap::new(OnionKeyPool::create(vec![])),
1559 obj,
1560 "converter::bool",
1561 OnionKeyPool::create(vec![]),
1562 &native_bool_converter,
1563 );
1564 return f(converter.weak());
1565 }
1566 "bytes" => {
1567 let converter = wrap_native_function(
1568 LambdaParameter::Multiple(Box::new([])),
1569 OnionFastMap::new(OnionKeyPool::create(vec![])),
1570 obj,
1571 "converter::bytes",
1572 OnionKeyPool::create(vec![]),
1573 &native_bytes_converter,
1574 );
1575 return f(converter.weak());
1576 }
1577 _ => {}
1578 }
1579 }
1580 Err(RuntimeError::InvalidOperation(
1581 format!(
1582 "Attribute '{}' not found for Integer",
1583 match key {
1584 OnionObject::String(s) => s.as_ref(),
1585 _ => "<non-string>",
1586 }
1587 )
1588 .into(),
1589 ))
1590 }
1591 OnionObject::Float(_) => {
1592 if let OnionObject::String(key_str) = key {
1593 match key_str.as_ref() {
1594 "int" => {
1595 let converter = wrap_native_function(
1596 LambdaParameter::Multiple(Box::new([])),
1597 OnionFastMap::new(OnionKeyPool::create(vec![])),
1598 obj,
1599 "converter::int",
1600 OnionKeyPool::create(vec![]),
1601 &native_int_converter,
1602 );
1603 return f(converter.weak());
1604 }
1605 "float" => {
1606 let converter = wrap_native_function(
1607 LambdaParameter::Multiple(Box::new([])),
1608 OnionFastMap::new(OnionKeyPool::create(vec![])),
1609 obj,
1610 "converter::float",
1611 OnionKeyPool::create(vec![]),
1612 &native_float_converter,
1613 );
1614 return f(converter.weak());
1615 }
1616 "string" => {
1617 let converter = wrap_native_function(
1618 LambdaParameter::Multiple(Box::new([])),
1619 OnionFastMap::new(OnionKeyPool::create(vec![])),
1620 obj,
1621 "converter::string",
1622 OnionKeyPool::create(vec![]),
1623 &native_string_converter,
1624 );
1625 return f(converter.weak());
1626 }
1627 "bool" => {
1628 let converter = wrap_native_function(
1629 LambdaParameter::Multiple(Box::new([])),
1630 OnionFastMap::new(OnionKeyPool::create(vec![])),
1631 obj,
1632 "converter::bool",
1633 OnionKeyPool::create(vec![]),
1634 &native_bool_converter,
1635 );
1636 return f(converter.weak());
1637 }
1638 "bytes" => {
1639 let converter = wrap_native_function(
1640 LambdaParameter::Multiple(Box::new([])),
1641 OnionFastMap::new(OnionKeyPool::create(vec![])),
1642 obj,
1643 "converter::bytes",
1644 OnionKeyPool::create(vec![]),
1645 &native_bytes_converter,
1646 );
1647 return f(converter.weak());
1648 }
1649 _ => {}
1650 }
1651 }
1652 Err(RuntimeError::InvalidOperation(
1653 format!(
1654 "Attribute '{}' not found for Float",
1655 match key {
1656 OnionObject::String(s) => s.as_ref(),
1657 _ => "<non-string>",
1658 }
1659 )
1660 .into(),
1661 ))
1662 }
1663 OnionObject::Boolean(_) => {
1664 if let OnionObject::String(key_str) = key {
1665 match key_str.as_ref() {
1666 "int" => {
1667 let converter = wrap_native_function(
1668 LambdaParameter::Multiple(Box::new([])),
1669 OnionFastMap::new(OnionKeyPool::create(vec![])),
1670 obj,
1671 "converter::int",
1672 OnionKeyPool::create(vec![]),
1673 &native_int_converter,
1674 );
1675 return f(converter.weak());
1676 }
1677 "float" => {
1678 let converter = wrap_native_function(
1679 LambdaParameter::Multiple(Box::new([])),
1680 OnionFastMap::new(OnionKeyPool::create(vec![])),
1681 obj,
1682 "converter::float",
1683 OnionKeyPool::create(vec![]),
1684 &native_float_converter,
1685 );
1686 return f(converter.weak());
1687 }
1688 "string" => {
1689 let converter = wrap_native_function(
1690 LambdaParameter::Multiple(Box::new([])),
1691 OnionFastMap::new(OnionKeyPool::create(vec![])),
1692 obj,
1693 "converter::string",
1694 OnionKeyPool::create(vec![]),
1695 &native_string_converter,
1696 );
1697 return f(converter.weak());
1698 }
1699 "bool" => {
1700 let converter = wrap_native_function(
1701 LambdaParameter::Multiple(Box::new([])),
1702 OnionFastMap::new(OnionKeyPool::create(vec![])),
1703 obj,
1704 "converter::bool",
1705 OnionKeyPool::create(vec![]),
1706 &native_bool_converter,
1707 );
1708 return f(converter.weak());
1709 }
1710 "bytes" => {
1711 let converter = wrap_native_function(
1712 LambdaParameter::Multiple(Box::new([])),
1713 OnionFastMap::new(OnionKeyPool::create(vec![])),
1714 obj,
1715 "converter::bytes",
1716 OnionKeyPool::create(vec![]),
1717 &native_bytes_converter,
1718 );
1719 return f(converter.weak());
1720 }
1721 _ => {}
1722 }
1723 }
1724 Err(RuntimeError::InvalidOperation(
1725 format!(
1726 "Attribute '{}' not found for Boolean",
1727 match key {
1728 OnionObject::String(s) => s.as_ref(),
1729 _ => "<non-string>",
1730 }
1731 )
1732 .into(),
1733 ))
1734 }
1735 OnionObject::Tuple(tuple) => {
1736 if let Ok(result) = tuple.with_attribute(key, f) {
1738 return Ok(result);
1739 }
1740
1741 if let OnionObject::String(key_str) = key {
1743 match key_str.as_ref() {
1744 "int" => {
1745 let converter = wrap_native_function(
1746 LambdaParameter::Multiple(Box::new([])),
1747 OnionFastMap::new(OnionKeyPool::create(vec![])),
1748 obj,
1749 "converter::int",
1750 OnionKeyPool::create(vec![]),
1751 &native_int_converter,
1752 );
1753 return f(converter.weak());
1754 }
1755 "float" => {
1756 let converter = wrap_native_function(
1757 LambdaParameter::Multiple(Box::new([])),
1758 OnionFastMap::new(OnionKeyPool::create(vec![])),
1759 obj,
1760 "converter::float",
1761 OnionKeyPool::create(vec![]),
1762 &native_float_converter,
1763 );
1764 return f(converter.weak());
1765 }
1766 "string" => {
1767 let converter = wrap_native_function(
1768 LambdaParameter::Multiple(Box::new([])),
1769 OnionFastMap::new(OnionKeyPool::create(vec![])),
1770 obj,
1771 "converter::string",
1772 OnionKeyPool::create(vec![]),
1773 &native_string_converter,
1774 );
1775 return f(converter.weak());
1776 }
1777 "bool" => {
1778 let converter = wrap_native_function(
1779 LambdaParameter::Multiple(Box::new([])),
1780 OnionFastMap::new(OnionKeyPool::create(vec![])),
1781 obj,
1782 "converter::bool",
1783 OnionKeyPool::create(vec![]),
1784 &native_bool_converter,
1785 );
1786 return f(converter.weak());
1787 }
1788 "bytes" => {
1789 let converter = wrap_native_function(
1790 LambdaParameter::Multiple(Box::new([])),
1791 OnionFastMap::new(OnionKeyPool::create(vec![])),
1792 obj,
1793 "converter::bytes",
1794 OnionKeyPool::create(vec![]),
1795 &native_bytes_converter,
1796 );
1797 return f(converter.weak());
1798 }
1799 "length" => {
1800 let length_method = wrap_native_function(
1801 LambdaParameter::Multiple(Box::new([])),
1802 OnionFastMap::new(OnionKeyPool::create(vec![])),
1803 obj,
1804 "builtin::length",
1805 OnionKeyPool::create(vec![]),
1806 &native_length_method,
1807 );
1808 return f(length_method.weak());
1809 }
1810 "elements" => {
1811 let elements_method = wrap_native_function(
1812 LambdaParameter::Multiple(Box::new([])),
1813 OnionFastMap::new(OnionKeyPool::create(vec![])),
1814 obj,
1815 "builtin::elements",
1816 OnionKeyPool::create(vec![]),
1817 &native_elements_method,
1818 );
1819 return f(elements_method.weak());
1820 }
1821 _ => {}
1822 }
1823 }
1824 Err(RuntimeError::InvalidOperation(
1825 format!(
1826 "Attribute '{}' not found for Tuple",
1827 match key {
1828 OnionObject::String(s) => s.as_ref(),
1829 _ => "<non-string>",
1830 }
1831 )
1832 .into(),
1833 ))
1834 }
1835 OnionObject::Pair(pair) => pair.with_attribute(key, f),
1836 OnionObject::Lambda(lambda) => lambda.0.with_attribute(key, f),
1837 OnionObject::LazySet(lazy_set) => lazy_set.with_attribute(key, f),
1838 OnionObject::String(_) => {
1839 if let OnionObject::String(key_str) = key {
1840 match key_str.as_ref() {
1841 "int" => {
1842 let converter = wrap_native_function(
1843 LambdaParameter::Multiple(Box::new([])),
1844 OnionFastMap::new(OnionKeyPool::create(vec![])),
1845 obj,
1846 "converter::int",
1847 OnionKeyPool::create(vec![]),
1848 &native_int_converter,
1849 );
1850 return f(converter.weak());
1851 }
1852 "float" => {
1853 let converter = wrap_native_function(
1854 LambdaParameter::Multiple(Box::new([])),
1855 OnionFastMap::new(OnionKeyPool::create(vec![])),
1856 obj,
1857 "converter::float",
1858 OnionKeyPool::create(vec![]),
1859 &native_float_converter,
1860 );
1861 return f(converter.weak());
1862 }
1863 "string" => {
1864 let converter = wrap_native_function(
1865 LambdaParameter::Multiple(Box::new([])),
1866 OnionFastMap::new(OnionKeyPool::create(vec![])),
1867 obj,
1868 "converter::string",
1869 OnionKeyPool::create(vec![]),
1870 &native_string_converter,
1871 );
1872 return f(converter.weak());
1873 }
1874 "bool" => {
1875 let converter = wrap_native_function(
1876 LambdaParameter::Multiple(Box::new([])),
1877 OnionFastMap::new(OnionKeyPool::create(vec![])),
1878 obj,
1879 "converter::bool",
1880 OnionKeyPool::create(vec![]),
1881 &native_bool_converter,
1882 );
1883 return f(converter.weak());
1884 }
1885 "bytes" => {
1886 let converter = wrap_native_function(
1887 LambdaParameter::Multiple(Box::new([])),
1888 OnionFastMap::new(OnionKeyPool::create(vec![])),
1889 obj,
1890 "converter::bytes",
1891 OnionKeyPool::create(vec![]),
1892 &native_bytes_converter,
1893 );
1894 return f(converter.weak());
1895 }
1896 "length" => {
1897 let length_method = wrap_native_function(
1898 LambdaParameter::Multiple(Box::new([])),
1899 OnionFastMap::new(OnionKeyPool::create(vec![])),
1900 obj,
1901 "builtin::length",
1902 OnionKeyPool::create(vec![]),
1903 &native_length_method,
1904 );
1905 return f(length_method.weak());
1906 }
1907 "elements" => {
1908 let elements_method = wrap_native_function(
1909 LambdaParameter::Multiple(Box::new([])),
1910 OnionFastMap::new(OnionKeyPool::create(vec![])),
1911 obj,
1912 "builtin::elements",
1913 OnionKeyPool::create(vec![]),
1914 &native_elements_method,
1915 );
1916 return f(elements_method.weak());
1917 }
1918 _ => {}
1919 }
1920 }
1921 Err(RuntimeError::InvalidOperation(
1922 format!(
1923 "Attribute '{}' not found for String",
1924 match key {
1925 OnionObject::String(s) => s.as_ref(),
1926 _ => "<non-string>",
1927 }
1928 )
1929 .into(),
1930 ))
1931 }
1932 OnionObject::Bytes(_) => {
1933 if let OnionObject::String(key_str) = key {
1934 match key_str.as_ref() {
1935 "int" => {
1936 let converter = wrap_native_function(
1937 LambdaParameter::Multiple(Box::new([])),
1938 OnionFastMap::new(OnionKeyPool::create(vec![])),
1939 obj,
1940 "converter::int",
1941 OnionKeyPool::create(vec![]),
1942 &native_int_converter,
1943 );
1944 return f(converter.weak());
1945 }
1946 "float" => {
1947 let converter = wrap_native_function(
1948 LambdaParameter::Multiple(Box::new([])),
1949 OnionFastMap::new(OnionKeyPool::create(vec![])),
1950 obj,
1951 "converter::float",
1952 OnionKeyPool::create(vec![]),
1953 &native_float_converter,
1954 );
1955 return f(converter.weak());
1956 }
1957 "string" => {
1958 let converter = wrap_native_function(
1959 LambdaParameter::Multiple(Box::new([])),
1960 OnionFastMap::new(OnionKeyPool::create(vec![])),
1961 obj,
1962 "converter::string",
1963 OnionKeyPool::create(vec![]),
1964 &native_string_converter,
1965 );
1966 return f(converter.weak());
1967 }
1968 "bool" => {
1969 let converter = wrap_native_function(
1970 LambdaParameter::Multiple(Box::new([])),
1971 OnionFastMap::new(OnionKeyPool::create(vec![])),
1972 obj,
1973 "converter::bool",
1974 OnionKeyPool::create(vec![]),
1975 &native_bool_converter,
1976 );
1977 return f(converter.weak());
1978 }
1979 "bytes" => {
1980 let converter = wrap_native_function(
1981 LambdaParameter::Multiple(Box::new([])),
1982 OnionFastMap::new(OnionKeyPool::create(vec![])),
1983 obj,
1984 "converter::bytes",
1985 OnionKeyPool::create(vec![]),
1986 &native_bytes_converter,
1987 );
1988 return f(converter.weak());
1989 }
1990 "length" => {
1991 let length_method = wrap_native_function(
1992 LambdaParameter::Multiple(Box::new([])),
1993 OnionFastMap::new(OnionKeyPool::create(vec![])),
1994 obj,
1995 "builtin::length",
1996 OnionKeyPool::create(vec![]),
1997 &native_length_method,
1998 );
1999 return f(length_method.weak());
2000 }
2001 "elements" => {
2002 let elements_method = wrap_native_function(
2003 LambdaParameter::Multiple(Box::new([])),
2004 OnionFastMap::new(OnionKeyPool::create(vec![])),
2005 obj,
2006 "builtin::elements",
2007 OnionKeyPool::create(vec![]),
2008 &native_elements_method,
2009 );
2010 return f(elements_method.weak());
2011 }
2012 _ => {}
2013 }
2014 }
2015 Err(RuntimeError::InvalidOperation(
2016 format!(
2017 "Attribute '{}' not found for Bytes",
2018 match key {
2019 OnionObject::String(s) => s.as_ref(),
2020 _ => "<non-string>",
2021 }
2022 )
2023 .into(),
2024 ))
2025 }
2026 OnionObject::Range(_, _) => {
2027 if let OnionObject::String(key_str) = key {
2028 match key_str.as_ref() {
2029 "int" => {
2030 let converter = wrap_native_function(
2031 LambdaParameter::Multiple(Box::new([])),
2032 OnionFastMap::new(OnionKeyPool::create(vec![])),
2033 obj,
2034 "converter::int",
2035 OnionKeyPool::create(vec![]),
2036 &native_int_converter,
2037 );
2038 return f(converter.weak());
2039 }
2040 "float" => {
2041 let converter = wrap_native_function(
2042 LambdaParameter::Multiple(Box::new([])),
2043 OnionFastMap::new(OnionKeyPool::create(vec![])),
2044 obj,
2045 "converter::float",
2046 OnionKeyPool::create(vec![]),
2047 &native_float_converter,
2048 );
2049 return f(converter.weak());
2050 }
2051 "string" => {
2052 let converter = wrap_native_function(
2053 LambdaParameter::Multiple(Box::new([])),
2054 OnionFastMap::new(OnionKeyPool::create(vec![])),
2055 obj,
2056 "converter::string",
2057 OnionKeyPool::create(vec![]),
2058 &native_string_converter,
2059 );
2060 return f(converter.weak());
2061 }
2062 "bool" => {
2063 let converter = wrap_native_function(
2064 LambdaParameter::Multiple(Box::new([])),
2065 OnionFastMap::new(OnionKeyPool::create(vec![])),
2066 obj,
2067 "converter::bool",
2068 OnionKeyPool::create(vec![]),
2069 &native_bool_converter,
2070 );
2071 return f(converter.weak());
2072 }
2073 "bytes" => {
2074 let converter = wrap_native_function(
2075 LambdaParameter::Multiple(Box::new([])),
2076 OnionFastMap::new(OnionKeyPool::create(vec![])),
2077 obj,
2078 "converter::bytes",
2079 OnionKeyPool::create(vec![]),
2080 &native_bytes_converter,
2081 );
2082 return f(converter.weak());
2083 }
2084 "length" => {
2085 let length_method = wrap_native_function(
2086 LambdaParameter::Multiple(Box::new([])),
2087 OnionFastMap::new(OnionKeyPool::create(vec![])),
2088 obj,
2089 "builtin::length",
2090 OnionKeyPool::create(vec![]),
2091 &native_length_method,
2092 );
2093 return f(length_method.weak());
2094 }
2095 "elements" => {
2096 let elements_method = wrap_native_function(
2097 LambdaParameter::Multiple(Box::new([])),
2098 OnionFastMap::new(OnionKeyPool::create(vec![])),
2099 obj,
2100 "builtin::elements",
2101 OnionKeyPool::create(vec![]),
2102 &native_elements_method,
2103 );
2104 return f(elements_method.weak());
2105 }
2106 _ => {}
2107 }
2108 }
2109 Err(RuntimeError::InvalidOperation(
2110 format!(
2111 "Attribute '{}' not found for Range",
2112 match key {
2113 OnionObject::String(s) => s.as_ref(),
2114 _ => "<non-string>",
2115 }
2116 )
2117 .into(),
2118 ))
2119 }
2120 OnionObject::Null => {
2121 if let OnionObject::String(key_str) = key {
2122 match key_str.as_ref() {
2123 "string" => {
2124 let converter = wrap_native_function(
2125 LambdaParameter::Multiple(Box::new([])),
2126 OnionFastMap::new(OnionKeyPool::create(vec![])),
2127 obj,
2128 "converter::string",
2129 OnionKeyPool::create(vec![]),
2130 &native_string_converter,
2131 );
2132 return f(converter.weak());
2133 }
2134 "bool" => {
2135 let converter = wrap_native_function(
2136 LambdaParameter::Multiple(Box::new([])),
2137 OnionFastMap::new(OnionKeyPool::create(vec![])),
2138 obj,
2139 "converter::bool",
2140 OnionKeyPool::create(vec![]),
2141 &native_bool_converter,
2142 );
2143 return f(converter.weak());
2144 }
2145 _ => {}
2146 }
2147 }
2148 Err(RuntimeError::InvalidOperation(
2149 format!(
2150 "Attribute '{}' not found for null",
2151 match key {
2152 OnionObject::String(s) => s.as_ref(),
2153 _ => "<non-string>",
2154 }
2155 )
2156 .into(),
2157 ))
2158 }
2159 OnionObject::Undefined(_) => {
2160 if let OnionObject::String(key_str) = key {
2161 match key_str.as_ref() {
2162 "string" => {
2163 let converter = wrap_native_function(
2164 LambdaParameter::Multiple(Box::new([])),
2165 OnionFastMap::new(OnionKeyPool::create(vec![])),
2166 obj,
2167 "converter::string",
2168 OnionKeyPool::create(vec![]),
2169 &native_string_converter,
2170 );
2171 return f(converter.weak());
2172 }
2173 "bool" => {
2174 let converter = wrap_native_function(
2175 LambdaParameter::Multiple(Box::new([])),
2176 OnionFastMap::new(OnionKeyPool::create(vec![])),
2177 obj,
2178 "converter::bool",
2179 OnionKeyPool::create(vec![]),
2180 &native_bool_converter,
2181 );
2182 return f(converter.weak());
2183 }
2184 _ => {}
2185 }
2186 }
2187 Err(RuntimeError::InvalidOperation(
2188 format!(
2189 "Attribute '{}' not found for undefined",
2190 match key {
2191 OnionObject::String(s) => s.as_ref(),
2192 _ => "<non-string>",
2193 }
2194 )
2195 .into(),
2196 ))
2197 }
2198 OnionObject::Custom(custom) => {
2199 let mut result: Result<R, RuntimeError> = Err(RuntimeError::InvalidOperation(
2200 "Custom with_attribute not called".into(),
2201 ));
2202 let mut closure = |obj: &OnionObject| -> Result<(), RuntimeError> {
2203 result = f(obj);
2204 Ok(())
2205 };
2206 custom.with_attribute(key, &mut closure)?;
2207 result
2208 }
2209 _ => Err(RuntimeError::InvalidOperation(
2210 format!("with_attribute() not supported for {:?}", self).into(),
2211 )),
2212 })
2213 }
2214
2215 pub fn apply(&self, value: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
2216 self.with_data(|obj| {
2217 value.with_data(|value| match obj {
2218 OnionObject::Tuple(tuple) => {
2219 match value {
2220 OnionObject::Integer(i) => {
2221 let elements = tuple.get_elements();
2223 if (*i as usize) < elements.len() {
2224 Ok(OnionStaticObject::new(elements[*i as usize].clone()))
2225 } else {
2226 Err(RuntimeError::InvalidOperation(
2227 "Index out of bounds for tuple".into(),
2228 ))
2229 }
2230 }
2231 OnionObject::Range(start, end) => {
2232 let elements = tuple.get_elements();
2234 let len = elements.len() as i64;
2235 let start_idx = (*start).max(0).min(len) as usize;
2236 let end_idx = (*end).max(0).min(len) as usize;
2237
2238 if start_idx <= end_idx {
2239 let sliced: Vec<OnionObject> =
2240 elements[start_idx..end_idx].to_vec();
2241 Ok(OnionStaticObject::new(OnionObject::Tuple(
2242 OnionTuple::new(sliced).into(),
2243 )))
2244 } else {
2245 Ok(OnionStaticObject::new(OnionObject::Tuple(
2246 OnionTuple::new(vec![]).into(),
2247 )))
2248 }
2249 }
2250 _ => Err(RuntimeError::InvalidType(
2251 "Tuple apply() expects Integer (index) or Range (slice)".into(),
2252 )),
2253 }
2254 }
2255 OnionObject::String(s) => {
2256 match value {
2257 OnionObject::Integer(i) => {
2258 if *i < 0 || *i >= s.chars().count() as i64 {
2260 return Err(RuntimeError::InvalidOperation(
2261 format!("Index out of bounds for String: {}", s).into(),
2262 ));
2263 }
2264 Ok(OnionStaticObject::new(OnionObject::String(Arc::from(
2265 s.chars().nth(*i as usize).unwrap().to_string(),
2266 ))))
2267 }
2268 OnionObject::Range(start, end) => {
2269 let chars: Vec<char> = s.chars().collect();
2271 let len = chars.len() as i64;
2272 let start_idx = (*start).max(0).min(len) as usize;
2273 let end_idx = (*end).max(0).min(len) as usize;
2274
2275 if start_idx <= end_idx {
2276 let sliced: String = chars[start_idx..end_idx].iter().collect();
2277 Ok(OnionStaticObject::new(OnionObject::String(Arc::from(
2278 sliced,
2279 ))))
2280 } else {
2281 Ok(OnionStaticObject::new(OnionObject::String(Arc::from(""))))
2282 }
2283 }
2284 _ => Err(RuntimeError::InvalidType(
2285 "String apply() expects Integer (index) or Range (slice)".into(),
2286 )),
2287 }
2288 }
2289 OnionObject::Bytes(b) => {
2290 match value {
2291 OnionObject::Integer(i) => {
2292 if *i < 0 || *i >= b.len() as i64 {
2294 return Err(RuntimeError::InvalidOperation(
2295 format!("Index out of bounds for Bytes: {:?}", b).into(),
2296 ));
2297 }
2298 Ok(OnionStaticObject::new(OnionObject::Bytes(Arc::from(vec![
2299 b[*i as usize],
2300 ]))))
2301 }
2302 OnionObject::Range(start, end) => {
2303 let len = b.len() as i64;
2305 let start_idx = (*start).max(0).min(len) as usize;
2306 let end_idx = (*end).max(0).min(len) as usize;
2307
2308 if start_idx <= end_idx {
2309 let sliced = &b[start_idx..end_idx];
2310 Ok(OnionStaticObject::new(OnionObject::Bytes(Arc::from(
2311 sliced,
2312 ))))
2313 } else {
2314 Ok(OnionStaticObject::new(OnionObject::Bytes(Arc::from(
2315 vec![],
2316 ))))
2317 }
2318 }
2319 _ => Err(RuntimeError::InvalidType(
2320 "Bytes apply() expects Integer (index) or Range (slice)".into(),
2321 )),
2322 }
2323 }
2324 OnionObject::Custom(custom) => custom.apply(value),
2325 _ => Err(RuntimeError::InvalidOperation(
2326 format!("apply() not supported for {:?}", obj).into(),
2327 )),
2328 })
2329 })
2330 }
2331
2332 pub fn key_of(&self) -> Result<OnionStaticObject, RuntimeError> {
2333 self.with_data(|obj| match obj {
2334 OnionObject::Pair(pair) => Ok(pair.get_key().stabilize()),
2335 OnionObject::Lambda(lambda) => Ok(lambda.0.get_parameter().to_onion()),
2336 OnionObject::LazySet(set) => Ok(set.get_container().stabilize()),
2337 OnionObject::Custom(custom) => custom.key_of(),
2338 _ => Err(RuntimeError::InvalidOperation(
2339 format!("key_of() not supported for {:?}", obj).into(),
2340 )),
2341 })
2342 }
2343
2344 pub fn value_of(&self) -> Result<OnionStaticObject, RuntimeError> {
2345 self.with_data(|obj| match obj {
2346 OnionObject::Pair(pair) => Ok(pair.get_value().stabilize()),
2347 OnionObject::LazySet(set) => Ok(set.get_filter().stabilize()),
2348 OnionObject::Undefined(s) => Ok(OnionStaticObject::new(OnionObject::String(
2349 Arc::from(s.as_ref().map(|o| o.as_ref()).unwrap_or_else(|| "")),
2350 ))),
2351 OnionObject::Custom(custom) => custom.value_of(),
2352 _ => Err(RuntimeError::InvalidOperation(
2353 format!("value_of() not supported for {:?}", obj).into(),
2354 )),
2355 })
2356 }
2357
2358 pub fn type_of(&self) -> Result<String, RuntimeError> {
2359 self.with_data(|obj| match obj {
2360 OnionObject::Integer(_) => Ok("Integer".to_string()),
2361 OnionObject::Float(_) => Ok("Float".to_string()),
2362 OnionObject::String(_) => Ok("String".to_string()),
2363 OnionObject::Bytes(_) => Ok("Bytes".to_string()),
2364 OnionObject::Boolean(_) => Ok("Boolean".to_string()),
2365 OnionObject::Null => Ok("Null".to_string()),
2366 OnionObject::Undefined(_) => Ok("Undefined".to_string()),
2367 OnionObject::Tuple(_) => Ok("Tuple".to_string()),
2368 OnionObject::Pair(_) => Ok("Pair".to_string()),
2369 OnionObject::LazySet(_) => Ok("LazySet".to_string()),
2370 OnionObject::InstructionPackage(_) => Ok("InstructionPackage".to_string()),
2371 OnionObject::Lambda(_) => Ok("Lambda".to_string()),
2372 OnionObject::Custom(custom) => custom.type_of(),
2373 _ => Err(RuntimeError::InvalidOperation(
2374 format!("type_of() not supported for {:?}", obj).into(),
2375 )),
2376 })
2377 }
2378
2379 #[inline(always)]
2380 pub fn copy(&self) -> Result<OnionStaticObject, RuntimeError> {
2381 self.with_data(|obj| Ok(obj.stabilize()))
2382 }
2383}
2384
2385#[derive(Clone)]
2386pub enum GCArcStorage {
2399 None,
2400 Single(GCArc<OnionObjectCell>),
2401 Multiple(Arc<Vec<GCArc<OnionObjectCell>>>),
2402}
2403
2404#[derive(Clone)]
2416pub struct OnionStaticObject {
2443 _arcs: GCArcStorage,
2444 obj: OnionObject,
2445}
2446
2447impl Default for OnionStaticObject {
2448 fn default() -> Self {
2449 OnionStaticObject {
2450 obj: OnionObject::Undefined(None),
2451 _arcs: GCArcStorage::None,
2452 }
2453 }
2454}
2455
2456impl Debug for OnionStaticObject {
2457 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2458 write!(f, "OnionStaticObject({:?})", self.obj)
2459 }
2460}
2461
2462impl Display for OnionStaticObject {
2463 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2464 write!(f, "OnionStaticObject({:?})", self.obj)
2465 }
2466}
2467
2468impl OnionStaticObject {
2469 #[inline(always)]
2470 pub fn new(obj: OnionObject) -> Self {
2471 let arcs = match &obj {
2472 OnionObject::Mut(obj) => match obj.upgrade() {
2473 None => GCArcStorage::None,
2474 Some(arc) => GCArcStorage::Single(arc),
2475 },
2476 OnionObject::Boolean(_)
2477 | OnionObject::Integer(_)
2478 | OnionObject::Float(_)
2479 | OnionObject::String(_)
2480 | OnionObject::Bytes(_)
2481 | OnionObject::Null
2482 | OnionObject::Undefined(_)
2483 | OnionObject::Range(_, _)
2484 | OnionObject::InstructionPackage(_) => GCArcStorage::None,
2485 _ => {
2486 let mut arcs = vec![];
2487 obj.upgrade(&mut arcs);
2488 match arcs.len() {
2489 0 => GCArcStorage::None,
2490 1 => GCArcStorage::Single(arcs[0].clone()),
2491 _ => GCArcStorage::Multiple(Arc::new(arcs)),
2492 }
2493 }
2494 };
2495 OnionStaticObject {
2496 obj: obj,
2497 _arcs: arcs,
2498 }
2499 }
2500
2501 #[inline(always)]
2502 pub fn weak(&self) -> &OnionObject {
2503 &self.obj
2504 }
2505
2506 #[inline(always)]
2507 pub fn mutablize(self, gc: &mut GC<OnionObjectCell>) -> OnionStaticObject {
2510 match self.weak() {
2511 OnionObject::Mut(_) => self,
2512 v => v.clone().mutablize(gc),
2513 }
2514 }
2515
2516 #[inline(always)]
2517 pub fn immutablize(self) -> Result<OnionStaticObject, RuntimeError> {
2520 match self.weak() {
2521 OnionObject::Mut(v) => match v.upgrade() {
2522 None => Err(RuntimeError::BrokenReference),
2523 Some(arc) => match arc.as_ref().0.read() {
2524 Ok(data) => Ok(OnionStaticObject::new(data.clone())),
2525 Err(_) => Err(RuntimeError::BrokenReference),
2526 },
2527 },
2528 _ => Ok(self),
2529 }
2530 }
2531}
2532
2533#[macro_export]
2535macro_rules! unwrap_object {
2536 ($obj:expr, $variant:path) => {
2537 match $obj {
2538 $variant(o) => Ok(o),
2539 _ => Err(RuntimeError::InvalidType(
2540 format!("Expected {}, found {:?}", stringify!($variant), $obj).into(),
2541 )),
2542 }
2543 };
2544}
2545
2546#[cfg(test)]
2547mod tests {
2548 use super::*;
2549 use std::time::Instant;
2550
2551 #[test]
2552 fn test_detailed_memory_sizes() {
2553 println!("详细内存分析:");
2554 println!(
2555 "OnionObjectCell: {} bytes",
2556 std::mem::size_of::<OnionObjectCell>()
2557 );
2558 println!("OnionObject: {} bytes", std::mem::size_of::<OnionObject>());
2559 println!(
2560 "OnionStaticObject: {} bytes",
2561 std::mem::size_of::<OnionStaticObject>()
2562 );
2563 println!(
2564 "GCArcStorage: {} bytes",
2565 std::mem::size_of::<GCArcStorage>()
2566 );
2567 println!(
2568 "GCArc<OnionObjectCell>: {} bytes",
2569 std::mem::size_of::<GCArc<OnionObjectCell>>()
2570 );
2571 println!("Arc<String>: {} bytes", std::mem::size_of::<Arc<String>>());
2572 println!(
2573 "Arc<Vec<u8>>: {} bytes",
2574 std::mem::size_of::<Arc<Vec<u8>>>()
2575 );
2576 println!(
2577 "GCArcWeak<OnionObjectCell>: {} bytes",
2578 std::mem::size_of::<GCArcWeak<OnionObjectCell>>()
2579 );
2580 println!("OnionTuple: {} bytes", std::mem::size_of::<OnionTuple>());
2581 println!("OnionPair: {} bytes", std::mem::size_of::<OnionPair>());
2582 println!(
2583 "OnionLazySet: {} bytes",
2584 std::mem::size_of::<OnionLazySet>()
2585 );
2586 }
2587
2588 #[test]
2589 fn benchmark_realistic_vm_operations() {
2590 println!("真实VM操作性能测试 (使用OnionStaticObject + clone):");
2591
2592 let start = Instant::now();
2594 let mut result_sum = 0i64;
2595
2596 for i in 0..5_000_000 {
2597 let obj1 = OnionObject::Integer(i).stabilize();
2599 let obj2 = OnionObject::Integer(i + 1).stabilize();
2600
2601 let result = obj1.weak().with_data(|data1| {
2603 obj2.weak().with_data(|data2| {
2604 match (data1, data2) {
2606 (OnionObject::Integer(a), OnionObject::Integer(b)) => {
2607 Ok(OnionObject::Integer(a + b).stabilize())
2608 }
2609 _ => Err(RuntimeError::InvalidOperation("Type error".into())),
2610 }
2611 })
2612 });
2613
2614 if let Ok(sum) = result {
2615 if let Ok(val) = sum.weak().with_data(|data| match data {
2617 OnionObject::Integer(v) => Ok(*v),
2618 _ => Err(RuntimeError::InvalidType("Not integer".into())),
2619 }) {
2620 result_sum += val;
2621 }
2622 }
2623 }
2624
2625 let duration = start.elapsed();
2626 println!("500万次VM风格整数运算: {:.2}s", duration.as_secs_f64());
2627 println!("每秒操作数: {:.0}", 5_000_000.0 / duration.as_secs_f64());
2628 println!("结果校验: {}", result_sum);
2629 }
2630
2631 #[test]
2632 fn benchmark_vm_style_arithmetic() {
2633 println!("VM风格算术运算性能测试:");
2634
2635 let start = Instant::now();
2636 let mut final_result = 0i64;
2637
2638 for i in 0..2_000_000 {
2639 let left = OnionObject::Integer(i).stabilize();
2641 let right = OnionObject::Integer(i + 1).stabilize();
2642
2643 if let Ok(result) = left
2645 .weak()
2646 .with_data(|l_data| right.weak().with_data(|r_data| l_data.binary_add(r_data)))
2647 {
2648 let multiplier = OnionObject::Integer(2).stabilize();
2650 if let Ok(mul_result) = result.weak().with_data(|add_data| {
2651 multiplier
2652 .weak()
2653 .with_data(|mul_data| add_data.binary_mul(mul_data))
2654 }) {
2655 if let Ok(val) = mul_result.weak().with_data(|data| data.to_integer()) {
2657 final_result += val;
2658 }
2659 }
2660 }
2661 }
2662
2663 let duration = start.elapsed();
2664 println!("200万次复合运算: {:.2}s", duration.as_secs_f64());
2665 println!("每秒操作数: {:.0}", 2_000_000.0 / duration.as_secs_f64());
2666 println!("最终结果: {}", final_result);
2667 }
2668
2669 #[test]
2670 fn benchmark_object_creation_overhead() {
2671 println!("对象创建开销测试:");
2672
2673 let start = Instant::now();
2675 let mut objects = Vec::with_capacity(1_000_000);
2676
2677 for i in 0..1_000_000 {
2678 let obj = OnionObject::Integer(i).stabilize();
2679 objects.push(obj);
2680 }
2681
2682 let creation_time = start.elapsed();
2683 println!(
2684 "100万个OnionStaticObject创建: {:.2}s",
2685 creation_time.as_secs_f64()
2686 );
2687
2688 let start = Instant::now();
2690 let mut sum = 0i64;
2691
2692 for obj in &objects {
2693 if let Ok(val) = obj.weak().with_data(|data| data.to_integer()) {
2694 sum += val;
2695 }
2696 }
2697
2698 let access_time = start.elapsed();
2699 println!("100万次对象访问: {:.2}s", access_time.as_secs_f64());
2700 println!("访问校验和: {}", sum);
2701
2702 let start = Instant::now();
2704 let mut cloned_objects = Vec::with_capacity(objects.len());
2705
2706 for obj in &objects[..100_000] {
2707 cloned_objects.push(obj.clone());
2709 }
2710
2711 let clone_time = start.elapsed();
2712 println!("10万个对象克隆: {:.2}s", clone_time.as_secs_f64());
2713 }
2714
2715 #[test]
2716 fn benchmark_string_operations_realistic() {
2717 println!("真实字符串操作性能测试:");
2718
2719 let start = Instant::now();
2720 let mut total_length = 0usize;
2721
2722 for i in 0..500_000 {
2723 let str_obj = OnionObject::String(Arc::from(format!("string_{}", i))).stabilize();
2725
2726 if let Ok(len_obj) = str_obj.weak().with_data(|data| data.len()) {
2728 if let Ok(length) = len_obj.weak().with_data(|data| data.to_integer()) {
2729 total_length += length as usize;
2730 }
2731 }
2732
2733 let suffix = OnionObject::String(Arc::from("_suffix".to_string())).stabilize();
2735 if let Ok(concat_result) = str_obj.weak().with_data(|str_data| {
2736 suffix
2737 .weak()
2738 .with_data(|suffix_data| str_data.binary_add(suffix_data))
2739 }) {
2740 if let Ok(concat_str) = concat_result
2742 .weak()
2743 .with_data(|data| data.to_string(&mut vec![]))
2744 {
2745 total_length += concat_str.len();
2746 }
2747 }
2748 }
2749
2750 let duration = start.elapsed();
2751 println!("50万次字符串操作: {:.2}s", duration.as_secs_f64());
2752 println!("每秒操作数: {:.0}", 500_000.0 / duration.as_secs_f64());
2753 println!("总字符串长度: {}", total_length);
2754 }
2755
2756 #[test]
2757 fn benchmark_refcell_overhead() {
2758 println!("RefCell开销分析:");
2759
2760 let direct_integers: Vec<i64> = (0..1_000_000).collect();
2762 let wrapped_integers: Vec<OnionStaticObject> = (0..1_000_000)
2763 .map(|i| OnionObject::Integer(i).stabilize())
2764 .collect();
2765
2766 let start = Instant::now();
2768 let mut sum1 = 0i64;
2769 for &val in &direct_integers {
2770 sum1 += val * 2;
2771 }
2772 let direct_time = start.elapsed();
2773
2774 let start = Instant::now();
2776 let mut sum2 = 0i64;
2777 for obj in &wrapped_integers {
2778 if let Ok(val) = obj.weak().with_data(|data| match data {
2779 OnionObject::Integer(i) => Ok(*i),
2780 _ => Err(RuntimeError::InvalidType("Not integer".into())),
2781 }) {
2782 sum2 += val * 2;
2783 }
2784 }
2785 let refcell_time = start.elapsed();
2786
2787 println!("直接访问100万个i64: {:.2}s", direct_time.as_secs_f64());
2788 println!(
2789 "RefCell访问100万个OnionObject: {:.2}s",
2790 refcell_time.as_secs_f64()
2791 );
2792 println!(
2793 "RefCell开销倍数: {:.1}x",
2794 refcell_time.as_secs_f64() / direct_time.as_secs_f64()
2795 );
2796 println!("校验: {} vs {}", sum1, sum2);
2797 }
2798}