1use std::{
2 collections::VecDeque,
3 fmt::{Debug, Display},
4 ptr::addr_eq,
5 sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
6};
7
8use crate::{
9 lambda::runnable::RuntimeError,
10 types::lambda::{
11 native::{
12 native_bool_converter, native_bytes_converter, native_elements_method,
13 native_float_converter, native_int_converter, native_length_method,
14 native_string_converter, wrap_native_function,
15 },
16 parameter::LambdaParameter,
17 },
18 utils::fastmap::{OnionFastMap, OnionKeyPool},
19};
20use arc_gc::{
21 arc::{GCArc, GCArcWeak},
22 gc::GC,
23 traceable::GCTraceable,
24};
25use base64::{Engine as _, engine::general_purpose};
26
27use super::{
28 lambda::{
29 definition::OnionLambdaDefinition, vm_instructions::instruction_set::VMInstructionPackage,
30 },
31 lazy_set::OnionLazySet,
32 pair::OnionPair,
33 tuple::OnionTuple,
34};
35
36pub struct OnionObjectCell(pub RwLock<OnionObject>);
38
39impl OnionObjectCell {
40 #[inline(always)]
41 pub fn with_data<T, F>(&self, f: F) -> Result<T, RuntimeError>
44 where
45 F: FnOnce(&OnionObject) -> Result<T, RuntimeError>,
46 {
47 match self.0.read() {
48 Ok(guard) => match &*guard {
49 OnionObject::Mut(_) => {
50 panic!(
51 "CRITICAL: OnionObjectCell contains Mut object. This indicates a bug in VM object allocation or GC logic. Check mutablize() and object creation paths."
52 )
53 }
54 obj => f(obj),
55 },
56 Err(_) => Err(RuntimeError::BorrowError(
57 "Failed to borrow OnionObjectCell at 'with_data'"
58 .to_string()
59 .into(),
60 )),
61 }
62 }
63 #[inline(always)]
64 pub fn with_data_mut<T, F>(&self, f: F) -> Result<T, RuntimeError>
67 where
68 F: FnOnce(&mut OnionObject) -> Result<T, RuntimeError>,
69 {
70 match self.0.write() {
71 Ok(mut guard) => match &mut *guard {
72 OnionObject::Mut(_) => {
73 panic!(
74 "CRITICAL: OnionObjectCell contains Mut object. This indicates a bug in VM object allocation or GC logic. Check mutablize() and object creation paths."
75 )
76 }
77 obj => f(obj),
78 },
79 Err(_) => Err(RuntimeError::BorrowError(
80 "Failed to borrow OnionObjectCell at 'with_data_mut'"
81 .to_string()
82 .into(),
83 )),
84 }
85 }
86
87 #[inline(always)]
88 pub fn with_attribute<T, F>(&self, key: &OnionObject, f: &F) -> Result<T, RuntimeError>
89 where
90 F: Fn(&OnionObject) -> Result<T, RuntimeError>,
91 {
92 self.0
93 .read()
94 .map_err(|_| {
95 RuntimeError::BorrowError(
96 "Failed to borrow OnionObjectCell at 'with_attribute'"
97 .to_string()
98 .into(),
99 )
100 })?
101 .with_attribute(key, f)
102 }
103
104 #[inline(always)]
105 pub fn upgrade(&self, collected: &mut Vec<GCArc<OnionObjectCell>>) {
106 match self.0.read() {
107 Ok(obj) => obj.upgrade(collected),
108 Err(_) => {
109 }
112 }
113 }
114
115 #[inline(always)]
116 pub fn stabilize(self) -> OnionStaticObject {
117 OnionStaticObject::new(self.try_borrow().unwrap().clone())
118 }
119
120 #[inline(always)]
121 pub fn equals(&self, other: &Self) -> Result<bool, RuntimeError> {
122 self.with_data(|obj| other.with_data(|other_obj| obj.equals(other_obj)))
123 }
124
125 #[inline(always)]
126 pub fn repr(&self, ptrs: &Vec<*const OnionObject>) -> Result<String, RuntimeError> {
127 self.with_data(|obj| obj.repr(ptrs))
128 }
129
130 #[inline(always)]
131 pub fn try_borrow(&self) -> Result<RwLockReadGuard<OnionObject>, RuntimeError> {
132 self.0.read().map_err(|_| {
133 RuntimeError::BorrowError(
134 "Failed to borrow OnionObjectCell at 'try_borrow'"
135 .to_string()
136 .into(),
137 )
138 })
139 }
140 #[inline(always)]
141 pub fn try_borrow_mut(&self) -> Result<RwLockWriteGuard<OnionObject>, RuntimeError> {
142 self.0.write().map_err(|_| {
143 RuntimeError::BorrowError(
144 "Failed to borrow OnionObjectCell at 'try_borrow_mut'"
145 .to_string()
146 .into(),
147 )
148 })
149 }
150}
151
152impl std::ops::Deref for OnionObjectCell {
153 type Target = RwLock<OnionObject>;
154
155 fn deref(&self) -> &Self::Target {
156 &self.0
157 }
158}
159
160impl std::ops::DerefMut for OnionObjectCell {
161 fn deref_mut(&mut self) -> &mut Self::Target {
162 &mut self.0
163 }
164}
165
166impl From<RwLock<OnionObject>> for OnionObjectCell {
167 fn from(cell: RwLock<OnionObject>) -> Self {
168 OnionObjectCell(cell)
169 }
170}
171
172impl From<OnionObject> for OnionObjectCell {
173 fn from(obj: OnionObject) -> Self {
174 OnionObjectCell(RwLock::new(obj))
175 }
176}
177
178impl GCTraceable<OnionObjectCell> for OnionObjectCell {
179 fn collect(&self, queue: &mut VecDeque<GCArcWeak<OnionObjectCell>>) {
180 if let Ok(obj) = self.0.read() {
181 obj.collect(queue);
182 }
183 }
184}
185
186impl Debug for OnionObjectCell {
187 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
188 write!(f, "{:?}", self.0.read())
189 }
190}
191
192impl Display for OnionObjectCell {
193 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
194 write!(f, "{:?}", self.0.read())
195 }
196}
197
198#[derive(Clone)]
199pub enum OnionObject {
204 Integer(i64),
206 Float(f64),
207 String(Arc<str>),
208 Bytes(Arc<[u8]>),
209 Boolean(bool),
210 Range(i64, i64),
211 Null,
212 Undefined(Option<Arc<str>>),
213 InstructionPackage(Arc<VMInstructionPackage>),
214
215 Tuple(Arc<OnionTuple>),
217 Pair(Arc<OnionPair>),
218 LazySet(Arc<OnionLazySet>),
219 Lambda((Arc<OnionLambdaDefinition>, Arc<OnionObject>)), Custom(Arc<dyn OnionObjectExt>),
221
222 Mut(GCArcWeak<OnionObjectCell>),
225}
226
227pub trait OnionObjectExt: GCTraceable<OnionObjectCell> + Debug + Send + Sync + 'static {
228 fn as_any(&self) -> &dyn std::any::Any;
230
231 fn upgrade(&self, collected: &mut Vec<GCArc<OnionObjectCell>>);
233
234 fn to_integer(&self) -> Result<i64, RuntimeError> {
236 Err(RuntimeError::InvalidType(
237 format!("Cannot convert {:?} to Integer", self).into(),
238 ))
239 }
240 fn to_float(&self) -> Result<f64, RuntimeError> {
241 Err(RuntimeError::InvalidType(
242 format!("Cannot convert {:?} to Float", self).into(),
243 ))
244 }
245 #[allow(unused_variables)]
246 fn to_string(&self, ptrs: &Vec<*const OnionObject>) -> Result<String, RuntimeError> {
247 Err(RuntimeError::InvalidType(
248 format!("Cannot convert {:?} to String", self).into(),
249 ))
250 }
251 fn to_bytes(&self) -> Result<Box<[u8]>, RuntimeError> {
252 Err(RuntimeError::InvalidType(
253 format!("Cannot convert {:?} to Bytes", self).into(),
254 ))
255 }
256 fn to_boolean(&self) -> Result<bool, RuntimeError> {
257 Err(RuntimeError::InvalidType(
258 format!("Cannot convert {:?} to Boolean", self).into(),
259 ))
260 }
261 #[allow(unused_variables)]
262 fn repr(&self, ptrs: &Vec<*const OnionObject>) -> Result<String, RuntimeError> {
263 Ok(format!("{:?}", self))
264 }
265 fn type_of(&self) -> Result<String, RuntimeError> {
266 Err(RuntimeError::InvalidType(
267 format!("Cannot get type of {:?}", self).into(),
268 ))
269 }
270
271 fn len(&self) -> Result<OnionStaticObject, RuntimeError> {
273 Err(RuntimeError::InvalidOperation(
274 format!("len() not supported for {:?}", self).into(),
275 ))
276 }
277 fn contains(&self, other: &OnionObject) -> Result<bool, RuntimeError> {
278 Err(RuntimeError::InvalidOperation(
279 format!("contains() not supported for {:?} and {:?}", self, other).into(),
280 ))
281 }
282 fn apply(&self, value: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
283 Err(RuntimeError::InvalidOperation(
284 format!(
285 "apply() not supported for {:?} with value {:?}",
286 self, value
287 )
288 .into(),
289 ))
290 }
291
292 fn key_of(&self) -> Result<OnionStaticObject, RuntimeError> {
294 Err(RuntimeError::InvalidOperation(
295 format!("key_of() not supported for {:?}", self).into(),
296 ))
297 }
298 fn value_of(&self) -> Result<OnionStaticObject, RuntimeError> {
299 Err(RuntimeError::InvalidOperation(
300 format!("value_of() not supported for {:?}", self).into(),
301 ))
302 }
303 #[allow(unused_variables)]
304 fn with_attribute(
305 &self,
306 key: &OnionObject,
307 f: &mut dyn FnMut(&OnionObject) -> Result<(), RuntimeError>,
308 ) -> Result<(), RuntimeError> {
309 Err(RuntimeError::InvalidOperation(
310 format!(
311 "with_attribute() not supported for {:?} with key {:?}",
312 self, key
313 )
314 .into(),
315 ))
316 }
317
318 fn equals(&self, other: &OnionObject) -> Result<bool, RuntimeError>;
320 fn is_same(&self, other: &OnionObject) -> Result<bool, RuntimeError>;
321 fn binary_eq(&self, other: &OnionObject) -> Result<bool, RuntimeError> {
322 Err(RuntimeError::InvalidOperation(
323 format!("binary_eq() not supported for {:?} and {:?}", self, other).into(),
324 ))
325 }
326 fn binary_lt(&self, other: &OnionObject) -> Result<bool, RuntimeError> {
327 Err(RuntimeError::InvalidOperation(
328 format!("binary_lt() not supported for {:?} and {:?}", self, other).into(),
329 ))
330 }
331 fn binary_gt(&self, other: &OnionObject) -> Result<bool, RuntimeError> {
332 Err(RuntimeError::InvalidOperation(
333 format!("binary_gt() not supported for {:?} and {:?}", self, other).into(),
334 ))
335 }
336
337 fn binary_add(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
339 Err(RuntimeError::InvalidOperation(
340 format!("binary_add() not supported for {:?} and {:?}", self, other).into(),
341 ))
342 }
343 fn binary_sub(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
344 Err(RuntimeError::InvalidOperation(
345 format!("binary_sub() not supported for {:?} and {:?}", self, other).into(),
346 ))
347 }
348 fn binary_mul(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
349 Err(RuntimeError::InvalidOperation(
350 format!("binary_mul() not supported for {:?} and {:?}", self, other).into(),
351 ))
352 }
353 fn binary_div(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
354 Err(RuntimeError::InvalidOperation(
355 format!("binary_div() not supported for {:?} and {:?}", self, other).into(),
356 ))
357 }
358 fn binary_mod(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
359 Err(RuntimeError::InvalidOperation(
360 format!("binary_mod() not supported for {:?} and {:?}", self, other).into(),
361 ))
362 }
363 fn binary_pow(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
364 Err(RuntimeError::InvalidOperation(
365 format!("binary_pow() not supported for {:?} and {:?}", self, other).into(),
366 ))
367 }
368
369 fn binary_and(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
371 Err(RuntimeError::InvalidOperation(
372 format!("binary_and() not supported for {:?} and {:?}", self, other).into(),
373 ))
374 }
375 fn binary_or(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
376 Err(RuntimeError::InvalidOperation(
377 format!("binary_or() not supported for {:?} and {:?}", self, other).into(),
378 ))
379 }
380 fn binary_xor(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
381 Err(RuntimeError::InvalidOperation(
382 format!("binary_xor() not supported for {:?} and {:?}", self, other).into(),
383 ))
384 }
385
386 fn binary_shl(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
388 Err(RuntimeError::InvalidOperation(
389 format!("binary_shl() not supported for {:?} and {:?}", self, other).into(),
390 ))
391 }
392 fn binary_shr(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
393 Err(RuntimeError::InvalidOperation(
394 format!("binary_shr() not supported for {:?} and {:?}", self, other).into(),
395 ))
396 }
397
398 fn unary_neg(&self) -> Result<OnionStaticObject, RuntimeError> {
400 Err(RuntimeError::InvalidOperation(
401 format!("unary_neg() not supported for {:?}", self).into(),
402 ))
403 }
404 fn unary_plus(&self) -> Result<OnionStaticObject, RuntimeError> {
405 Err(RuntimeError::InvalidOperation(
406 format!("unary_plus() not supported for {:?}", self).into(),
407 ))
408 }
409 fn unary_not(&self) -> Result<OnionStaticObject, RuntimeError> {
410 Err(RuntimeError::InvalidOperation(
411 format!("unary_not() not supported for {:?}", self).into(),
412 ))
413 }
414}
415
416impl Debug for OnionObject {
417 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
418 write!(
420 f,
421 "{}",
422 self.repr(&vec![])
423 .unwrap_or_else(|_| "BrokenReference".to_string())
424 )
425 }
426}
427
428impl GCTraceable<OnionObjectCell> for OnionObject {
429 fn collect(&self, queue: &mut VecDeque<GCArcWeak<OnionObjectCell>>) {
430 match self {
431 OnionObject::Mut(weak) => {
432 queue.push_back(weak.clone());
433 }
434 OnionObject::Tuple(tuple) => tuple.collect(queue),
435 OnionObject::Pair(pair) => pair.collect(queue),
436 OnionObject::LazySet(lazy_set) => lazy_set.collect(queue),
437 OnionObject::Lambda(lambda) => {
438 lambda.0.collect(queue);
439 lambda.1.collect(queue);
440 }
441 OnionObject::Custom(custom) => custom.collect(queue),
442
443 _ => {}
444 }
445 }
446}
447impl OnionObject {
448 pub fn upgrade(&self, collected: &mut Vec<GCArc<OnionObjectCell>>) {
449 match self {
450 OnionObject::Mut(weak) => {
451 if let Some(strong) = weak.upgrade() {
452 collected.push(strong);
453 }
454 }
455 OnionObject::Tuple(tuple) => tuple.upgrade(collected),
456 OnionObject::Pair(pair) => pair.upgrade(collected),
457 OnionObject::LazySet(lazy_set) => lazy_set.upgrade(collected),
458 OnionObject::Lambda(lambda) => {
459 lambda.0.upgrade(collected);
460 lambda.1.upgrade(collected);
461 }
462 OnionObject::Custom(custom) => custom.upgrade(collected),
463 _ => {}
464 }
465 }
466
467 #[inline(always)]
468 pub fn to_cell(self) -> OnionObjectCell {
469 OnionObjectCell(RwLock::new(self))
470 }
471
472 #[inline(always)]
473 pub fn stabilize(&self) -> OnionStaticObject {
474 OnionStaticObject::new(self.clone())
475 }
476
477 #[inline(always)]
478 pub fn consume_and_stabilize(self) -> OnionStaticObject {
479 OnionStaticObject::new(self)
480 }
481 pub fn len(&self) -> Result<OnionStaticObject, RuntimeError> {
482 self.with_data(|obj| match obj {
483 OnionObject::Tuple(tuple) => tuple.len(),
484 OnionObject::String(s) => {
485 Ok(OnionStaticObject::new(OnionObject::Integer(s.len() as i64)))
486 }
487 OnionObject::Bytes(b) => {
488 Ok(OnionStaticObject::new(OnionObject::Integer(b.len() as i64)))
489 }
490 OnionObject::Range(start, end) => Ok(OnionStaticObject::new(OnionObject::Integer(
491 (end - start) as i64,
492 ))),
493 OnionObject::Custom(custom) => custom.len(),
494 _ => Err(RuntimeError::InvalidOperation(
495 format!("len() not supported for {:?}", self).into(),
496 )),
497 })
498 }
499
500 pub fn contains(&self, other: &OnionObject) -> Result<bool, RuntimeError> {
501 self.with_data(|obj| {
502 other.with_data(|other_obj| match (obj, other_obj) {
503 (OnionObject::Tuple(tuple), _) => tuple.contains(other_obj),
504 (OnionObject::String(s), OnionObject::String(other_s)) => {
505 Ok(s.contains(other_s.as_ref()))
506 }
507 (OnionObject::Bytes(b), OnionObject::Bytes(other_b)) => Ok(b
508 .windows(other_b.len())
509 .any(|window| window.eq(other_b.as_ref()))),
510 (OnionObject::Range(l, r), OnionObject::Integer(i)) => Ok(*i >= *l && *i < *r),
511 (OnionObject::Range(start, end), OnionObject::Float(f)) => {
512 Ok(*f >= *start as f64 && *f < *end as f64)
513 }
514 (OnionObject::Range(start, end), OnionObject::Range(other_start, other_end)) => {
515 Ok(*other_start >= *start && *other_end <= *end)
516 }
517 (OnionObject::Custom(custom), _) => custom.contains(other_obj),
518 _ => Err(RuntimeError::InvalidOperation(
519 format!("contains() not supported for {:?}", obj).into(),
520 )),
521 })
522 })
523 }
524
525 #[inline(always)]
526 pub fn with_data<T, F>(&self, f: F) -> Result<T, RuntimeError>
527 where
528 F: FnOnce(&OnionObject) -> Result<T, RuntimeError>,
529 {
530 match self {
531 OnionObject::Mut(weak) => {
532 if let Some(strong) = weak.upgrade() {
533 strong.as_ref().with_data(f)
534 } else {
535 Err(RuntimeError::BrokenReference)
536 }
537 }
538 _ => f(self),
539 }
540 }
541
542 #[inline(always)]
543 pub fn with_data_mut<T, F>(&mut self, f: F) -> Result<T, RuntimeError>
544 where
545 F: FnOnce(&mut OnionObject) -> Result<T, RuntimeError>,
546 {
547 match self {
548 OnionObject::Mut(weak) => {
549 if let Some(strong) = weak.upgrade() {
550 strong.as_ref().with_data_mut(f)
551 } else {
552 Err(RuntimeError::BrokenReference)
553 }
554 }
555 _ => f(self),
556 }
557 }
558
559 #[inline(always)]
560 pub fn assign(&self, other: &OnionObject) -> Result<(), RuntimeError> {
562 let OnionObject::Mut(weak) = self else {
565 return Err(RuntimeError::InvalidOperation(
566 format!("Cannot assign to non-mutable object: {:?}", self).into(),
567 ));
568 };
569 match weak.upgrade() {
570 Some(strong) => {
571 let new_value = other.with_data(|other| Ok(other.clone()))?;
573
574 strong.as_ref().with_data_mut(|obj| {
576 *obj = new_value;
577 Ok(())
578 })
579 }
580 None => Err(RuntimeError::BrokenReference),
581 }
582 }
583
584 pub fn to_integer(&self) -> Result<i64, RuntimeError> {
585 self.with_data(|obj| match obj {
586 OnionObject::Integer(i) => Ok(*i),
587 OnionObject::Float(f) => Ok(*f as i64),
588 OnionObject::String(s) => s
589 .parse::<i64>()
590 .map_err(|e| RuntimeError::InvalidType(e.to_string().into())),
591 OnionObject::Boolean(b) => Ok(if *b { 1 } else { 0 }),
592 OnionObject::Custom(custom) => custom.to_integer(),
593 _ => Err(RuntimeError::InvalidType(
594 format!("Cannot convert {:?} to Integer", obj).into(),
595 )),
596 })
597 }
598 pub fn to_float(&self) -> Result<f64, RuntimeError> {
599 self.with_data(|obj| match obj {
600 OnionObject::Integer(i) => Ok(*i as f64),
601 OnionObject::Float(f) => Ok(*f),
602 OnionObject::String(s) => s
603 .parse::<f64>()
604 .map_err(|e| RuntimeError::InvalidType(e.to_string().into())),
605 OnionObject::Boolean(b) => Ok(if *b { 1.0 } else { 0.0 }),
606 OnionObject::Custom(custom) => custom.to_float(),
607 _ => Err(RuntimeError::InvalidType(
608 format!("Cannot convert {:?} to Float", obj).into(),
609 )),
610 })
611 }
612
613 pub fn to_string(&self, ptrs: &Vec<*const OnionObject>) -> Result<String, RuntimeError> {
614 self.with_data(|obj| {
615 for ptr in ptrs {
616 if addr_eq(obj, *ptr) {
617 return Ok("...".to_string());
618 }
619 }
620 let mut new_ptrs = ptrs.clone();
621 new_ptrs.push(obj);
622 match obj {
623 OnionObject::Integer(i) => Ok(i.to_string()),
624 OnionObject::Float(f) => Ok(f.to_string()),
625 OnionObject::String(s) => Ok(s.to_string()),
626 OnionObject::Bytes(b) => Ok(format!(
627 "$\"{}\"",
628 general_purpose::STANDARD.encode(b.as_ref())
629 )),
630 OnionObject::Boolean(b) => Ok(if *b {
631 "true".to_string()
632 } else {
633 "false".to_string()
634 }),
635 OnionObject::Null => Ok("null".to_string()),
636 OnionObject::Undefined(s) => Ok(match s {
637 Some(s) => format!("undefined({:?})", s),
638 None => "undefined".to_string(),
639 }),
640 OnionObject::Range(start, end) => Ok(format!("{}..{}", start, end)),
641 OnionObject::Tuple(tuple) => match tuple.get_elements().len() {
642 0 => Ok("()".to_string()),
643 1 => {
644 let first = tuple.get_elements().first().unwrap();
645 Ok(format!("({},)", first.repr(&new_ptrs)?))
646 }
647 _ => {
648 let elements: Result<Vec<String>, RuntimeError> = tuple
649 .get_elements()
650 .iter()
651 .map(|e| e.repr(&new_ptrs))
652 .collect();
653 Ok(format!("({})", elements?.join(", ")))
654 }
655 },
656 OnionObject::Pair(pair) => {
657 let left = pair.get_key().repr(&new_ptrs)?;
658 let right = pair.get_value().repr(&new_ptrs)?;
659 Ok(format!("{} : {}", left, right))
660 }
661 OnionObject::LazySet(lazy_set) => {
662 let container = lazy_set.get_container().repr(&new_ptrs)?;
663 let filter = lazy_set.get_filter().repr(&new_ptrs)?;
664 Ok(format!("[{} | {}]", container, filter))
665 }
666 OnionObject::InstructionPackage(_) => Ok("InstructionPackage(...)".to_string()),
667 OnionObject::Lambda(lambda) => {
668 let body = lambda.0.get_body().to_string();
669 Ok(format!(
670 "{}::{} -> {}",
671 lambda.0.get_signature(),
672 lambda.0.get_parameter(),
673 body
674 ))
675 }
676 OnionObject::Custom(custom) => custom.to_string(&new_ptrs),
677 _ => {
678 Ok(format!("{:?}", obj))
680 }
681 }
682 })
683 }
684
685 pub fn repr(&self, ptrs: &Vec<*const OnionObject>) -> Result<String, RuntimeError> {
686 self.with_data(|obj| {
687 for ptr in ptrs {
688 if addr_eq(obj, *ptr) {
689 return Ok("...".to_string());
690 }
691 }
692 let mut new_ptrs = ptrs.clone();
693 new_ptrs.push(obj);
694 match obj {
695 OnionObject::Integer(i) => Ok(format!("{}", i)),
696 OnionObject::Float(f) => Ok(format!("{}", f)),
697 OnionObject::String(s) => Ok(format!("{:?}", s)),
698 OnionObject::Bytes(b) => Ok(format!(
699 "$\"{}\"",
700 general_purpose::STANDARD.encode(b.as_ref())
701 )),
702 OnionObject::Boolean(b) => Ok(format!("{}", b)),
703 OnionObject::Null => Ok("null".to_string()),
704 OnionObject::Undefined(s) => Ok(match s {
705 Some(s) => format!("undefined({:?})", s),
706 None => "undefined".to_string(),
707 }),
708 OnionObject::Range(start, end) => Ok(format!("{}..{}", start, end)),
709 OnionObject::Tuple(tuple) => match tuple.get_elements().len() {
710 0 => Ok("()".to_string()),
711 1 => {
712 let first = tuple.get_elements().first().unwrap();
713 Ok(format!("({},)", first.repr(&new_ptrs)?))
714 }
715 _ => {
716 let elements: Result<Vec<String>, RuntimeError> = tuple
717 .get_elements()
718 .iter()
719 .map(|e| e.repr(&new_ptrs))
720 .collect();
721 Ok(format!("({})", elements?.join(", ")))
722 }
723 },
724 OnionObject::Pair(pair) => {
725 let left = pair.get_key().repr(&new_ptrs)?;
726 let right = pair.get_value().repr(&new_ptrs)?;
727 Ok(format!("{} : {}", left, right))
728 }
729 OnionObject::LazySet(lazy_set) => {
730 let container = lazy_set.get_container().repr(&new_ptrs)?;
731 let filter = lazy_set.get_filter().repr(&new_ptrs)?;
732 Ok(format!("[{} | {}]", container, filter))
733 }
734 OnionObject::InstructionPackage(_) => Ok("InstructionPackage(...)".to_string()),
735 OnionObject::Lambda(lambda) => Ok(format!(
736 "{}::{} -> {}",
737 lambda.0.get_signature(),
738 lambda.0.get_parameter(),
739 lambda.0.get_body()
740 )),
741 OnionObject::Mut(weak) => {
742 if let Some(strong) = weak.upgrade() {
743 let inner_repr = strong
744 .as_ref()
745 .try_borrow()
746 .map_err(|_| {
747 RuntimeError::BorrowError(
748 "Failed to borrow Mut object at 'repr'".into(),
749 )
750 })?
751 .repr(&new_ptrs)?;
752 Ok(format!("mut ({})", inner_repr))
753 } else {
754 Ok("Mut(BrokenReference)".to_string())
755 }
756 }
757 OnionObject::Custom(custom) => {
758 let custom_repr = custom.repr(&new_ptrs)?;
759 Ok(format!("Custom({})", custom_repr))
760 }
761 }
762 })
763 }
764 pub fn to_bytes(&self) -> Result<Box<[u8]>, RuntimeError> {
765 self.with_data(|obj| match obj {
766 OnionObject::Integer(i) => Ok(i.to_string().into_bytes().into_boxed_slice()),
767 OnionObject::Float(f) => Ok(f.to_string().into_bytes().into_boxed_slice()),
768 OnionObject::String(s) => Ok(s.as_bytes().to_vec().into_boxed_slice()),
769 OnionObject::Bytes(b) => Ok(b.as_ref().to_vec().into_boxed_slice()),
770 OnionObject::Boolean(b) => Ok(if *b {
771 b"true".to_vec().into_boxed_slice()
772 } else {
773 b"false".to_vec().into_boxed_slice()
774 }),
775 OnionObject::Custom(custom) => custom.to_bytes(),
776 _ => Err(RuntimeError::InvalidType(
777 format!("Cannot convert {:?} to Bytes", obj).into(),
778 )),
779 })
780 }
781
782 pub fn to_boolean(&self) -> Result<bool, RuntimeError> {
783 self.with_data(|obj| match obj {
784 OnionObject::Integer(i) => Ok(*i != 0),
785 OnionObject::Float(f) => Ok(*f != 0.0),
786 OnionObject::String(s) => Ok(!s.is_empty()),
787 OnionObject::Bytes(b) => Ok(!b.is_empty()),
788 OnionObject::Boolean(b) => Ok(*b),
789 OnionObject::Null => Ok(false),
790 OnionObject::Undefined(_) => Ok(false),
791 OnionObject::Custom(custom) => custom.to_boolean(),
792 _ => Err(RuntimeError::InvalidType(
793 format!("Cannot convert {:?} to Boolean", obj).into(),
794 )),
795 })
796 }
797
798 #[inline(always)]
799 fn mutablize(self, gc: &mut GC<OnionObjectCell>) -> OnionStaticObject {
800 let arc = gc.create(OnionObjectCell::from(self));
801 OnionStaticObject {
802 obj: OnionObject::Mut(arc.as_weak()),
803 _arcs: GCArcStorage::Single(arc),
804 }
805 }
806}
807
808impl OnionObject {
809 pub fn equals(&self, other: &Self) -> Result<bool, RuntimeError> {
810 self.with_data(|left| {
811 other.with_data(|right| {
812 match (left, right) {
813 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => Ok(i1 == i2),
814 (OnionObject::Float(f1), OnionObject::Float(f2)) => Ok(f1 == f2),
815 (OnionObject::Integer(i1), OnionObject::Float(f2)) => Ok(*i1 as f64 == *f2),
816 (OnionObject::Float(f1), OnionObject::Integer(i2)) => Ok(*f1 == *i2 as f64),
817 (OnionObject::String(s1), OnionObject::String(s2)) => Ok(s1 == s2),
818 (OnionObject::Bytes(b1), OnionObject::Bytes(b2)) => Ok(b1 == b2),
819 (OnionObject::Boolean(b1), OnionObject::Boolean(b2)) => Ok(b1 == b2),
820 (OnionObject::Range(start1, end1), OnionObject::Range(start2, end2)) => {
821 Ok(start1 == start2 && end1 == end2)
822 }
823 (OnionObject::Null, OnionObject::Null) => Ok(true),
824 (OnionObject::Undefined(_), OnionObject::Undefined(_)) => Ok(true),
825 (OnionObject::Tuple(t1), _) => t1.equals(other),
826 (OnionObject::Pair(p1), _) => p1.equals(other),
827 (OnionObject::Custom(c1), _) => c1.equals(other),
828
829 _ => Ok(false),
831 }
832 })
833 })
834 }
835 pub fn is_same(&self, other: &Self) -> Result<bool, RuntimeError> {
836 match (self, other) {
837 (OnionObject::Mut(weak1), OnionObject::Mut(weak2)) => {
838 if let (Some(strong1), Some(strong2)) = (weak1.upgrade(), weak2.upgrade()) {
839 Ok(addr_eq(strong1.as_ref(), strong2.as_ref()))
840 } else {
841 Ok(false)
842 }
843 }
844 (OnionObject::Custom(c1), _) => c1.is_same(other),
845 _ => self.equals(other),
846 }
847 }
848
849 pub fn binary_add(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
850 self.with_data(|obj| {
851 other.with_data(|other_obj| match (obj, other_obj) {
852 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => {
853 Ok(OnionStaticObject::new(OnionObject::Integer(i1 + i2)))
854 }
855 (OnionObject::Float(f1), OnionObject::Float(f2)) => {
856 Ok(OnionStaticObject::new(OnionObject::Float(f1 + f2)))
857 }
858 (OnionObject::Integer(i1), OnionObject::Float(f2)) => {
859 Ok(OnionStaticObject::new(OnionObject::Float(*i1 as f64 + f2)))
860 }
861 (OnionObject::Float(f1), OnionObject::Integer(i2)) => {
862 Ok(OnionStaticObject::new(OnionObject::Float(f1 + *i2 as f64)))
863 }
864 (OnionObject::String(s1), OnionObject::String(s2)) => Ok(OnionStaticObject::new(
865 OnionObject::String(Arc::from(format!("{}{}", s1, s2))),
866 )),
867 (OnionObject::Bytes(b1), OnionObject::Bytes(b2)) => {
868 let mut new_bytes = Vec::with_capacity(b1.len() + b2.len());
869 new_bytes.extend_from_slice(b1.as_ref());
870 new_bytes.extend_from_slice(b2.as_ref());
871 Ok(OnionStaticObject::new(OnionObject::Bytes(Arc::from(
872 new_bytes,
873 ))))
874 }
875 (OnionObject::Range(start1, end1), OnionObject::Range(start2, end2)) => Ok(
876 OnionStaticObject::new(OnionObject::Range(start1 + start2, end1 + end2)),
877 ),
878 (OnionObject::Tuple(t1), _) => t1.binary_add(other_obj),
879 (OnionObject::Custom(c1), _) => c1.binary_add(other_obj),
880 _ => Err(RuntimeError::InvalidOperation(
881 format!(
882 "Invalid binary add operation for {:?} and {:?}",
883 obj, other_obj
884 )
885 .into(),
886 )),
887 })
888 })
889 }
890
891 pub fn binary_sub(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
892 self.with_data(|obj| {
893 other.with_data(|other_obj| match (obj, other_obj) {
894 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => {
895 Ok(OnionStaticObject::new(OnionObject::Integer(i1 - i2)))
896 }
897 (OnionObject::Float(f1), OnionObject::Float(f2)) => {
898 Ok(OnionStaticObject::new(OnionObject::Float(f1 - f2)))
899 }
900 (OnionObject::Integer(i1), OnionObject::Float(f2)) => {
901 Ok(OnionStaticObject::new(OnionObject::Float(*i1 as f64 - f2)))
902 }
903 (OnionObject::Float(f1), OnionObject::Integer(i2)) => {
904 Ok(OnionStaticObject::new(OnionObject::Float(f1 - *i2 as f64)))
905 }
906 (OnionObject::Custom(c1), _) => c1.binary_sub(other_obj),
907 _ => Err(RuntimeError::InvalidOperation(
908 format!(
909 "Invalid binary sub operation for {:?} and {:?}",
910 obj, other_obj
911 )
912 .into(),
913 )),
914 })
915 })
916 }
917
918 pub fn binary_mul(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
919 self.with_data(|obj| {
920 other.with_data(|other_obj| match (obj, other_obj) {
921 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => {
922 Ok(OnionStaticObject::new(OnionObject::Integer(i1 * i2)))
923 }
924 (OnionObject::Float(f1), OnionObject::Float(f2)) => {
925 Ok(OnionStaticObject::new(OnionObject::Float(f1 * f2)))
926 }
927 (OnionObject::Integer(i1), OnionObject::Float(f2)) => {
928 Ok(OnionStaticObject::new(OnionObject::Float(*i1 as f64 * f2)))
929 }
930 (OnionObject::Float(f1), OnionObject::Integer(i2)) => {
931 Ok(OnionStaticObject::new(OnionObject::Float(f1 * *i2 as f64)))
932 }
933 (OnionObject::Custom(c1), _) => c1.binary_mul(other_obj),
934 _ => Err(RuntimeError::InvalidOperation(
935 format!(
936 "Invalid binary mul operation for {:?} and {:?}",
937 obj, other_obj
938 )
939 .into(),
940 )),
941 })
942 })
943 }
944
945 pub fn binary_div(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
946 self.with_data(|obj| {
947 other.with_data(|other_obj| match (obj, other_obj) {
948 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => {
949 if *i2 == 0 {
950 return Err(RuntimeError::InvalidOperation("Division by zero".into()));
951 }
952 Ok(OnionStaticObject::new(OnionObject::Integer(i1 / i2)))
953 }
954 (OnionObject::Float(f1), OnionObject::Float(f2)) => {
955 Ok(OnionStaticObject::new(OnionObject::Float(f1 / f2)))
956 }
957 (OnionObject::Integer(i1), OnionObject::Float(f2)) => {
958 Ok(OnionStaticObject::new(OnionObject::Float(*i1 as f64 / f2)))
959 }
960 (OnionObject::Float(f1), OnionObject::Integer(i2)) => {
961 Ok(OnionStaticObject::new(OnionObject::Float(f1 / *i2 as f64)))
962 }
963 (OnionObject::Custom(c1), _) => c1.binary_div(other_obj),
964 _ => Err(RuntimeError::InvalidOperation(
965 format!(
966 "Invalid binary div operation for {:?} and {:?}",
967 obj, other_obj
968 )
969 .into(),
970 )),
971 })
972 })
973 }
974
975 pub fn binary_mod(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
976 self.with_data(|obj| {
977 other.with_data(|other_obj| match (obj, other_obj) {
978 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => {
979 if *i2 == 0 {
980 return Err(RuntimeError::InvalidOperation("Division by zero".into()));
981 }
982 Ok(OnionStaticObject::new(OnionObject::Integer(i1 % i2)))
983 }
984 (OnionObject::Float(f1), OnionObject::Float(f2)) => {
985 Ok(OnionStaticObject::new(OnionObject::Float(f1 % f2)))
986 }
987 (OnionObject::Integer(i1), OnionObject::Float(f2)) => {
988 Ok(OnionStaticObject::new(OnionObject::Float(*i1 as f64 % f2)))
989 }
990 (OnionObject::Float(f1), OnionObject::Integer(i2)) => {
991 Ok(OnionStaticObject::new(OnionObject::Float(f1 % *i2 as f64)))
992 }
993 (OnionObject::Custom(c1), _) => c1.binary_mod(other_obj),
994 _ => Err(RuntimeError::InvalidOperation(
995 format!(
996 "Invalid binary mod operation for {:?} and {:?}",
997 obj, other_obj
998 )
999 .into(),
1000 )),
1001 })
1002 })
1003 }
1004
1005 pub fn binary_pow(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
1006 self.with_data(|obj| {
1007 other.with_data(|other_obj| match (obj, other_obj) {
1008 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => Ok(OnionStaticObject::new(
1009 OnionObject::Integer(i1.pow(*i2 as u32)),
1010 )),
1011 (OnionObject::Float(f1), OnionObject::Float(f2)) => {
1012 Ok(OnionStaticObject::new(OnionObject::Float(f1.powf(*f2))))
1013 }
1014 (OnionObject::Integer(i1), OnionObject::Float(f2)) => Ok(OnionStaticObject::new(
1015 OnionObject::Float((*i1 as f64).powf(*f2)),
1016 )),
1017 (OnionObject::Float(f1), OnionObject::Integer(i2)) => Ok(OnionStaticObject::new(
1018 OnionObject::Float(f1.powi(*i2 as i32)),
1019 )),
1020 (OnionObject::Custom(c1), _) => c1.binary_pow(other_obj),
1021 _ => Err(RuntimeError::InvalidOperation(
1022 format!(
1023 "Invalid binary pow operation for {:?} and {:?}",
1024 obj, other_obj
1025 )
1026 .into(),
1027 )),
1028 })
1029 })
1030 }
1031
1032 pub fn binary_and(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
1033 self.with_data(|obj| {
1034 other.with_data(|other_obj| match (obj, other_obj) {
1035 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => {
1036 Ok(OnionStaticObject::new(OnionObject::Integer(i1 & i2)))
1037 }
1038 (OnionObject::Boolean(f1), OnionObject::Boolean(f2)) => {
1039 Ok(OnionStaticObject::new(OnionObject::Boolean(*f1 && *f2)))
1040 }
1041 (OnionObject::Custom(c1), _) => c1.binary_and(other_obj),
1042 _ => Err(RuntimeError::InvalidOperation(
1043 format!(
1044 "Invalid binary and operation for {:?} and {:?}",
1045 obj, other_obj
1046 )
1047 .into(),
1048 )),
1049 })
1050 })
1051 }
1052
1053 pub fn binary_or(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
1054 self.with_data(|obj| {
1055 other.with_data(|other_obj| match (obj, other_obj) {
1056 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => {
1057 Ok(OnionStaticObject::new(OnionObject::Integer(i1 | i2)))
1058 }
1059 (OnionObject::Boolean(f1), OnionObject::Boolean(f2)) => {
1060 Ok(OnionStaticObject::new(OnionObject::Boolean(*f1 || *f2)))
1061 }
1062 (OnionObject::Custom(c1), _) => c1.binary_or(other_obj),
1063 _ => Err(RuntimeError::InvalidOperation(
1064 format!(
1065 "Invalid binary or operation for {:?} and {:?}",
1066 obj, other_obj
1067 )
1068 .into(),
1069 )),
1070 })
1071 })
1072 }
1073
1074 pub fn binary_xor(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
1075 self.with_data(|obj| {
1076 other.with_data(|other_obj| match (obj, other_obj) {
1077 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => {
1078 Ok(OnionStaticObject::new(OnionObject::Integer(i1 ^ i2)))
1079 }
1080 (OnionObject::Custom(c1), _) => c1.binary_xor(other_obj),
1081 _ => Err(RuntimeError::InvalidOperation(
1082 format!(
1083 "Invalid binary xor operation for {:?} and {:?}",
1084 obj, other_obj
1085 )
1086 .into(),
1087 )),
1088 })
1089 })
1090 }
1091
1092 pub fn binary_shl(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
1093 self.with_data(|obj| {
1094 other.with_data(|other_obj| match (obj, other_obj) {
1095 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => {
1096 Ok(OnionStaticObject::new(OnionObject::Integer(i1 << i2)))
1097 }
1098 (OnionObject::Custom(c1), _) => c1.binary_shl(other_obj),
1099 _ => Err(RuntimeError::InvalidOperation(
1100 format!(
1101 "Invalid binary shl operation for {:?} and {:?}",
1102 obj, other_obj
1103 )
1104 .into(),
1105 )),
1106 })
1107 })
1108 }
1109
1110 pub fn binary_shr(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
1111 self.with_data(|obj| {
1112 other.with_data(|other_obj| match (obj, other_obj) {
1113 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => {
1114 Ok(OnionStaticObject::new(OnionObject::Integer(i1 >> i2)))
1115 }
1116 (OnionObject::Custom(c1), _) => c1.binary_shr(other_obj),
1117 _ => Err(RuntimeError::InvalidOperation(
1118 format!(
1119 "Invalid binary shr operation for {:?} and {:?}",
1120 obj, other_obj
1121 )
1122 .into(),
1123 )),
1124 })
1125 })
1126 }
1127
1128 pub fn binary_eq(&self, other: &Self) -> Result<bool, RuntimeError> {
1129 self.equals(other)
1130 }
1131
1132 pub fn binary_lt(&self, other: &Self) -> Result<bool, RuntimeError> {
1133 self.with_data(|obj| {
1134 other.with_data(|other_obj| match (obj, other_obj) {
1135 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => Ok(i1 < i2),
1136 (OnionObject::Float(f1), OnionObject::Float(f2)) => Ok(f1 < f2),
1137 (OnionObject::Integer(i1), OnionObject::Float(f2)) => Ok((*i1 as f64) < *f2),
1138 (OnionObject::Float(f1), OnionObject::Integer(i2)) => Ok(*f1 < *i2 as f64),
1139 (OnionObject::Custom(c1), _) => c1.binary_lt(other_obj),
1140 _ => Err(RuntimeError::InvalidOperation(
1141 format!(
1142 "Invalid binary lt operation for {:?} and {:?}",
1143 obj, other_obj
1144 )
1145 .into(),
1146 )),
1147 })
1148 })
1149 }
1150
1151 pub fn binary_gt(&self, other: &Self) -> Result<bool, RuntimeError> {
1152 self.with_data(|obj| {
1153 other.with_data(|other_obj| match (obj, other_obj) {
1154 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => Ok(i1 > i2),
1155 (OnionObject::Float(f1), OnionObject::Float(f2)) => Ok(f1 > f2),
1156 (OnionObject::Integer(i1), OnionObject::Float(f2)) => Ok((*i1 as f64) > *f2),
1157 (OnionObject::Float(f1), OnionObject::Integer(i2)) => Ok(*f1 > *i2 as f64),
1158 (OnionObject::Custom(c1), _) => c1.binary_gt(other_obj),
1159 _ => Err(RuntimeError::InvalidOperation(
1160 format!(
1161 "Invalid binary gt operation for {:?} and {:?}",
1162 obj, other_obj
1163 )
1164 .into(),
1165 )),
1166 })
1167 })
1168 }
1169
1170 pub fn unary_neg(&self) -> Result<OnionStaticObject, RuntimeError> {
1171 self.with_data(|obj| match obj {
1172 OnionObject::Integer(i) => Ok(OnionStaticObject::new(OnionObject::Integer(-i))),
1173 OnionObject::Float(f) => Ok(OnionStaticObject::new(OnionObject::Float(-f))),
1174 OnionObject::Custom(custom) => custom.unary_neg(),
1175 _ => Err(RuntimeError::InvalidOperation(
1176 format!("Invalid unary neg operation for {:?}", obj).into(),
1177 )),
1178 })
1179 }
1180
1181 pub fn unary_plus(&self) -> Result<OnionStaticObject, RuntimeError> {
1182 self.with_data(|obj| match obj {
1183 OnionObject::Integer(i) => Ok(OnionStaticObject::new(OnionObject::Integer(i.abs()))),
1184 OnionObject::Float(f) => Ok(OnionStaticObject::new(OnionObject::Float(f.abs()))),
1185 OnionObject::Custom(custom) => custom.unary_plus(),
1186 _ => Err(RuntimeError::InvalidOperation(
1187 format!("Invalid unary plus operation for {:?}", obj).into(),
1188 )),
1189 })
1190 }
1191
1192 pub fn unary_not(&self) -> Result<OnionStaticObject, RuntimeError> {
1193 self.with_data(|obj| match obj {
1194 OnionObject::Boolean(b) => Ok(OnionStaticObject::new(OnionObject::Boolean(!b))),
1195 OnionObject::Integer(i) => Ok(OnionStaticObject::new(OnionObject::Integer(!i))),
1196 OnionObject::Custom(custom) => custom.unary_not(),
1197 _ => Err(RuntimeError::InvalidOperation(
1198 format!("Invalid unary not operation for {:?}", obj).into(),
1199 )),
1200 })
1201 }
1202
1203 pub fn with_attribute<F, R>(&self, key: &OnionObject, f: &F) -> Result<R, RuntimeError>
1204 where
1205 F: Fn(&OnionObject) -> Result<R, RuntimeError>,
1206 {
1207 self.with_data(|obj| match obj {
1208 OnionObject::Integer(_) => {
1209 if let OnionObject::String(key_str) = key {
1210 match key_str.as_ref() {
1211 "int" => {
1212 let converter = wrap_native_function(
1213 LambdaParameter::Multiple(Box::new([])),
1214 OnionFastMap::new(OnionKeyPool::create(vec![])),
1215 obj,
1216 "converter::int",
1217 OnionKeyPool::create(vec![]),
1218 &native_int_converter,
1219 );
1220 return f(converter.weak());
1221 }
1222 "float" => {
1223 let converter = wrap_native_function(
1224 LambdaParameter::Multiple(Box::new([])),
1225 OnionFastMap::new(OnionKeyPool::create(vec![])),
1226 obj,
1227 "converter::float",
1228 OnionKeyPool::create(vec![]),
1229 &native_float_converter,
1230 );
1231 return f(converter.weak());
1232 }
1233 "string" => {
1234 let converter = wrap_native_function(
1235 LambdaParameter::Multiple(Box::new([])),
1236 OnionFastMap::new(OnionKeyPool::create(vec![])),
1237 obj,
1238 "converter::string",
1239 OnionKeyPool::create(vec![]),
1240 &native_string_converter,
1241 );
1242 return f(converter.weak());
1243 }
1244 "bool" => {
1245 let converter = wrap_native_function(
1246 LambdaParameter::Multiple(Box::new([])),
1247 OnionFastMap::new(OnionKeyPool::create(vec![])),
1248 obj,
1249 "converter::bool",
1250 OnionKeyPool::create(vec![]),
1251 &native_bool_converter,
1252 );
1253 return f(converter.weak());
1254 }
1255 "bytes" => {
1256 let converter = wrap_native_function(
1257 LambdaParameter::Multiple(Box::new([])),
1258 OnionFastMap::new(OnionKeyPool::create(vec![])),
1259 obj,
1260 "converter::bytes",
1261 OnionKeyPool::create(vec![]),
1262 &native_bytes_converter,
1263 );
1264 return f(converter.weak());
1265 }
1266 _ => {}
1267 }
1268 }
1269 Err(RuntimeError::InvalidOperation(
1270 format!(
1271 "Attribute '{}' not found for Integer",
1272 match key {
1273 OnionObject::String(s) => s.as_ref(),
1274 _ => "<non-string>",
1275 }
1276 )
1277 .into(),
1278 ))
1279 }
1280 OnionObject::Float(_) => {
1281 if let OnionObject::String(key_str) = key {
1282 match key_str.as_ref() {
1283 "int" => {
1284 let converter = wrap_native_function(
1285 LambdaParameter::Multiple(Box::new([])),
1286 OnionFastMap::new(OnionKeyPool::create(vec![])),
1287 obj,
1288 "converter::int",
1289 OnionKeyPool::create(vec![]),
1290 &native_int_converter,
1291 );
1292 return f(converter.weak());
1293 }
1294 "float" => {
1295 let converter = wrap_native_function(
1296 LambdaParameter::Multiple(Box::new([])),
1297 OnionFastMap::new(OnionKeyPool::create(vec![])),
1298 obj,
1299 "converter::float",
1300 OnionKeyPool::create(vec![]),
1301 &native_float_converter,
1302 );
1303 return f(converter.weak());
1304 }
1305 "string" => {
1306 let converter = wrap_native_function(
1307 LambdaParameter::Multiple(Box::new([])),
1308 OnionFastMap::new(OnionKeyPool::create(vec![])),
1309 obj,
1310 "converter::string",
1311 OnionKeyPool::create(vec![]),
1312 &native_string_converter,
1313 );
1314 return f(converter.weak());
1315 }
1316 "bool" => {
1317 let converter = wrap_native_function(
1318 LambdaParameter::Multiple(Box::new([])),
1319 OnionFastMap::new(OnionKeyPool::create(vec![])),
1320 obj,
1321 "converter::bool",
1322 OnionKeyPool::create(vec![]),
1323 &native_bool_converter,
1324 );
1325 return f(converter.weak());
1326 }
1327 "bytes" => {
1328 let converter = wrap_native_function(
1329 LambdaParameter::Multiple(Box::new([])),
1330 OnionFastMap::new(OnionKeyPool::create(vec![])),
1331 obj,
1332 "converter::bytes",
1333 OnionKeyPool::create(vec![]),
1334 &native_bytes_converter,
1335 );
1336 return f(converter.weak());
1337 }
1338 _ => {}
1339 }
1340 }
1341 Err(RuntimeError::InvalidOperation(
1342 format!(
1343 "Attribute '{}' not found for Float",
1344 match key {
1345 OnionObject::String(s) => s.as_ref(),
1346 _ => "<non-string>",
1347 }
1348 )
1349 .into(),
1350 ))
1351 }
1352 OnionObject::Boolean(_) => {
1353 if let OnionObject::String(key_str) = key {
1354 match key_str.as_ref() {
1355 "int" => {
1356 let converter = wrap_native_function(
1357 LambdaParameter::Multiple(Box::new([])),
1358 OnionFastMap::new(OnionKeyPool::create(vec![])),
1359 obj,
1360 "converter::int",
1361 OnionKeyPool::create(vec![]),
1362 &native_int_converter,
1363 );
1364 return f(converter.weak());
1365 }
1366 "float" => {
1367 let converter = wrap_native_function(
1368 LambdaParameter::Multiple(Box::new([])),
1369 OnionFastMap::new(OnionKeyPool::create(vec![])),
1370 obj,
1371 "converter::float",
1372 OnionKeyPool::create(vec![]),
1373 &native_float_converter,
1374 );
1375 return f(converter.weak());
1376 }
1377 "string" => {
1378 let converter = wrap_native_function(
1379 LambdaParameter::Multiple(Box::new([])),
1380 OnionFastMap::new(OnionKeyPool::create(vec![])),
1381 obj,
1382 "converter::string",
1383 OnionKeyPool::create(vec![]),
1384 &native_string_converter,
1385 );
1386 return f(converter.weak());
1387 }
1388 "bool" => {
1389 let converter = wrap_native_function(
1390 LambdaParameter::Multiple(Box::new([])),
1391 OnionFastMap::new(OnionKeyPool::create(vec![])),
1392 obj,
1393 "converter::bool",
1394 OnionKeyPool::create(vec![]),
1395 &native_bool_converter,
1396 );
1397 return f(converter.weak());
1398 }
1399 "bytes" => {
1400 let converter = wrap_native_function(
1401 LambdaParameter::Multiple(Box::new([])),
1402 OnionFastMap::new(OnionKeyPool::create(vec![])),
1403 obj,
1404 "converter::bytes",
1405 OnionKeyPool::create(vec![]),
1406 &native_bytes_converter,
1407 );
1408 return f(converter.weak());
1409 }
1410 _ => {}
1411 }
1412 }
1413 Err(RuntimeError::InvalidOperation(
1414 format!(
1415 "Attribute '{}' not found for Boolean",
1416 match key {
1417 OnionObject::String(s) => s.as_ref(),
1418 _ => "<non-string>",
1419 }
1420 )
1421 .into(),
1422 ))
1423 }
1424 OnionObject::Tuple(tuple) => {
1425 if let Ok(result) = tuple.with_attribute(key, f) {
1427 return Ok(result);
1428 }
1429
1430 if let OnionObject::String(key_str) = key {
1432 match key_str.as_ref() {
1433 "int" => {
1434 let converter = wrap_native_function(
1435 LambdaParameter::Multiple(Box::new([])),
1436 OnionFastMap::new(OnionKeyPool::create(vec![])),
1437 obj,
1438 "converter::int",
1439 OnionKeyPool::create(vec![]),
1440 &native_int_converter,
1441 );
1442 return f(converter.weak());
1443 }
1444 "float" => {
1445 let converter = wrap_native_function(
1446 LambdaParameter::Multiple(Box::new([])),
1447 OnionFastMap::new(OnionKeyPool::create(vec![])),
1448 obj,
1449 "converter::float",
1450 OnionKeyPool::create(vec![]),
1451 &native_float_converter,
1452 );
1453 return f(converter.weak());
1454 }
1455 "string" => {
1456 let converter = wrap_native_function(
1457 LambdaParameter::Multiple(Box::new([])),
1458 OnionFastMap::new(OnionKeyPool::create(vec![])),
1459 obj,
1460 "converter::string",
1461 OnionKeyPool::create(vec![]),
1462 &native_string_converter,
1463 );
1464 return f(converter.weak());
1465 }
1466 "bool" => {
1467 let converter = wrap_native_function(
1468 LambdaParameter::Multiple(Box::new([])),
1469 OnionFastMap::new(OnionKeyPool::create(vec![])),
1470 obj,
1471 "converter::bool",
1472 OnionKeyPool::create(vec![]),
1473 &native_bool_converter,
1474 );
1475 return f(converter.weak());
1476 }
1477 "bytes" => {
1478 let converter = wrap_native_function(
1479 LambdaParameter::Multiple(Box::new([])),
1480 OnionFastMap::new(OnionKeyPool::create(vec![])),
1481 obj,
1482 "converter::bytes",
1483 OnionKeyPool::create(vec![]),
1484 &native_bytes_converter,
1485 );
1486 return f(converter.weak());
1487 }
1488 "length" => {
1489 let length_method = wrap_native_function(
1490 LambdaParameter::Multiple(Box::new([])),
1491 OnionFastMap::new(OnionKeyPool::create(vec![])),
1492 obj,
1493 "builtin::length",
1494 OnionKeyPool::create(vec![]),
1495 &native_length_method,
1496 );
1497 return f(length_method.weak());
1498 }
1499 "elements" => {
1500 let elements_method = wrap_native_function(
1501 LambdaParameter::Multiple(Box::new([])),
1502 OnionFastMap::new(OnionKeyPool::create(vec![])),
1503 obj,
1504 "builtin::elements",
1505 OnionKeyPool::create(vec![]),
1506 &native_elements_method,
1507 );
1508 return f(elements_method.weak());
1509 }
1510 _ => {}
1511 }
1512 }
1513 Err(RuntimeError::InvalidOperation(
1514 format!(
1515 "Attribute '{}' not found for Tuple",
1516 match key {
1517 OnionObject::String(s) => s.as_ref(),
1518 _ => "<non-string>",
1519 }
1520 )
1521 .into(),
1522 ))
1523 }
1524 OnionObject::Pair(pair) => pair.with_attribute(key, f),
1525 OnionObject::Lambda(lambda) => lambda.0.with_attribute(key, f),
1526 OnionObject::LazySet(lazy_set) => lazy_set.with_attribute(key, f),
1527 OnionObject::String(_) => {
1528 if let OnionObject::String(key_str) = key {
1529 match key_str.as_ref() {
1530 "int" => {
1531 let converter = wrap_native_function(
1532 LambdaParameter::Multiple(Box::new([])),
1533 OnionFastMap::new(OnionKeyPool::create(vec![])),
1534 obj,
1535 "converter::int",
1536 OnionKeyPool::create(vec![]),
1537 &native_int_converter,
1538 );
1539 return f(converter.weak());
1540 }
1541 "float" => {
1542 let converter = wrap_native_function(
1543 LambdaParameter::Multiple(Box::new([])),
1544 OnionFastMap::new(OnionKeyPool::create(vec![])),
1545 obj,
1546 "converter::float",
1547 OnionKeyPool::create(vec![]),
1548 &native_float_converter,
1549 );
1550 return f(converter.weak());
1551 }
1552 "string" => {
1553 let converter = wrap_native_function(
1554 LambdaParameter::Multiple(Box::new([])),
1555 OnionFastMap::new(OnionKeyPool::create(vec![])),
1556 obj,
1557 "converter::string",
1558 OnionKeyPool::create(vec![]),
1559 &native_string_converter,
1560 );
1561 return f(converter.weak());
1562 }
1563 "bool" => {
1564 let converter = wrap_native_function(
1565 LambdaParameter::Multiple(Box::new([])),
1566 OnionFastMap::new(OnionKeyPool::create(vec![])),
1567 obj,
1568 "converter::bool",
1569 OnionKeyPool::create(vec![]),
1570 &native_bool_converter,
1571 );
1572 return f(converter.weak());
1573 }
1574 "bytes" => {
1575 let converter = wrap_native_function(
1576 LambdaParameter::Multiple(Box::new([])),
1577 OnionFastMap::new(OnionKeyPool::create(vec![])),
1578 obj,
1579 "converter::bytes",
1580 OnionKeyPool::create(vec![]),
1581 &native_bytes_converter,
1582 );
1583 return f(converter.weak());
1584 }
1585 "length" => {
1586 let length_method = wrap_native_function(
1587 LambdaParameter::Multiple(Box::new([])),
1588 OnionFastMap::new(OnionKeyPool::create(vec![])),
1589 obj,
1590 "builtin::length",
1591 OnionKeyPool::create(vec![]),
1592 &native_length_method,
1593 );
1594 return f(length_method.weak());
1595 }
1596 "elements" => {
1597 let elements_method = wrap_native_function(
1598 LambdaParameter::Multiple(Box::new([])),
1599 OnionFastMap::new(OnionKeyPool::create(vec![])),
1600 obj,
1601 "builtin::elements",
1602 OnionKeyPool::create(vec![]),
1603 &native_elements_method,
1604 );
1605 return f(elements_method.weak());
1606 }
1607 _ => {}
1608 }
1609 }
1610 Err(RuntimeError::InvalidOperation(
1611 format!(
1612 "Attribute '{}' not found for String",
1613 match key {
1614 OnionObject::String(s) => s.as_ref(),
1615 _ => "<non-string>",
1616 }
1617 )
1618 .into(),
1619 ))
1620 }
1621 OnionObject::Bytes(_) => {
1622 if let OnionObject::String(key_str) = key {
1623 match key_str.as_ref() {
1624 "int" => {
1625 let converter = wrap_native_function(
1626 LambdaParameter::Multiple(Box::new([])),
1627 OnionFastMap::new(OnionKeyPool::create(vec![])),
1628 obj,
1629 "converter::int",
1630 OnionKeyPool::create(vec![]),
1631 &native_int_converter,
1632 );
1633 return f(converter.weak());
1634 }
1635 "float" => {
1636 let converter = wrap_native_function(
1637 LambdaParameter::Multiple(Box::new([])),
1638 OnionFastMap::new(OnionKeyPool::create(vec![])),
1639 obj,
1640 "converter::float",
1641 OnionKeyPool::create(vec![]),
1642 &native_float_converter,
1643 );
1644 return f(converter.weak());
1645 }
1646 "string" => {
1647 let converter = wrap_native_function(
1648 LambdaParameter::Multiple(Box::new([])),
1649 OnionFastMap::new(OnionKeyPool::create(vec![])),
1650 obj,
1651 "converter::string",
1652 OnionKeyPool::create(vec![]),
1653 &native_string_converter,
1654 );
1655 return f(converter.weak());
1656 }
1657 "bool" => {
1658 let converter = wrap_native_function(
1659 LambdaParameter::Multiple(Box::new([])),
1660 OnionFastMap::new(OnionKeyPool::create(vec![])),
1661 obj,
1662 "converter::bool",
1663 OnionKeyPool::create(vec![]),
1664 &native_bool_converter,
1665 );
1666 return f(converter.weak());
1667 }
1668 "bytes" => {
1669 let converter = wrap_native_function(
1670 LambdaParameter::Multiple(Box::new([])),
1671 OnionFastMap::new(OnionKeyPool::create(vec![])),
1672 obj,
1673 "converter::bytes",
1674 OnionKeyPool::create(vec![]),
1675 &native_bytes_converter,
1676 );
1677 return f(converter.weak());
1678 }
1679 "length" => {
1680 let length_method = wrap_native_function(
1681 LambdaParameter::Multiple(Box::new([])),
1682 OnionFastMap::new(OnionKeyPool::create(vec![])),
1683 obj,
1684 "builtin::length",
1685 OnionKeyPool::create(vec![]),
1686 &native_length_method,
1687 );
1688 return f(length_method.weak());
1689 }
1690 "elements" => {
1691 let elements_method = wrap_native_function(
1692 LambdaParameter::Multiple(Box::new([])),
1693 OnionFastMap::new(OnionKeyPool::create(vec![])),
1694 obj,
1695 "builtin::elements",
1696 OnionKeyPool::create(vec![]),
1697 &native_elements_method,
1698 );
1699 return f(elements_method.weak());
1700 }
1701 _ => {}
1702 }
1703 }
1704 Err(RuntimeError::InvalidOperation(
1705 format!(
1706 "Attribute '{}' not found for Bytes",
1707 match key {
1708 OnionObject::String(s) => s.as_ref(),
1709 _ => "<non-string>",
1710 }
1711 )
1712 .into(),
1713 ))
1714 }
1715 OnionObject::Range(_, _) => {
1716 if let OnionObject::String(key_str) = key {
1717 match key_str.as_ref() {
1718 "int" => {
1719 let converter = wrap_native_function(
1720 LambdaParameter::Multiple(Box::new([])),
1721 OnionFastMap::new(OnionKeyPool::create(vec![])),
1722 obj,
1723 "converter::int",
1724 OnionKeyPool::create(vec![]),
1725 &native_int_converter,
1726 );
1727 return f(converter.weak());
1728 }
1729 "float" => {
1730 let converter = wrap_native_function(
1731 LambdaParameter::Multiple(Box::new([])),
1732 OnionFastMap::new(OnionKeyPool::create(vec![])),
1733 obj,
1734 "converter::float",
1735 OnionKeyPool::create(vec![]),
1736 &native_float_converter,
1737 );
1738 return f(converter.weak());
1739 }
1740 "string" => {
1741 let converter = wrap_native_function(
1742 LambdaParameter::Multiple(Box::new([])),
1743 OnionFastMap::new(OnionKeyPool::create(vec![])),
1744 obj,
1745 "converter::string",
1746 OnionKeyPool::create(vec![]),
1747 &native_string_converter,
1748 );
1749 return f(converter.weak());
1750 }
1751 "bool" => {
1752 let converter = wrap_native_function(
1753 LambdaParameter::Multiple(Box::new([])),
1754 OnionFastMap::new(OnionKeyPool::create(vec![])),
1755 obj,
1756 "converter::bool",
1757 OnionKeyPool::create(vec![]),
1758 &native_bool_converter,
1759 );
1760 return f(converter.weak());
1761 }
1762 "bytes" => {
1763 let converter = wrap_native_function(
1764 LambdaParameter::Multiple(Box::new([])),
1765 OnionFastMap::new(OnionKeyPool::create(vec![])),
1766 obj,
1767 "converter::bytes",
1768 OnionKeyPool::create(vec![]),
1769 &native_bytes_converter,
1770 );
1771 return f(converter.weak());
1772 }
1773 "length" => {
1774 let length_method = wrap_native_function(
1775 LambdaParameter::Multiple(Box::new([])),
1776 OnionFastMap::new(OnionKeyPool::create(vec![])),
1777 obj,
1778 "builtin::length",
1779 OnionKeyPool::create(vec![]),
1780 &native_length_method,
1781 );
1782 return f(length_method.weak());
1783 }
1784 "elements" => {
1785 let elements_method = wrap_native_function(
1786 LambdaParameter::Multiple(Box::new([])),
1787 OnionFastMap::new(OnionKeyPool::create(vec![])),
1788 obj,
1789 "builtin::elements",
1790 OnionKeyPool::create(vec![]),
1791 &native_elements_method,
1792 );
1793 return f(elements_method.weak());
1794 }
1795 _ => {}
1796 }
1797 }
1798 Err(RuntimeError::InvalidOperation(
1799 format!(
1800 "Attribute '{}' not found for Range",
1801 match key {
1802 OnionObject::String(s) => s.as_ref(),
1803 _ => "<non-string>",
1804 }
1805 )
1806 .into(),
1807 ))
1808 }
1809 OnionObject::Custom(custom) => {
1810 let mut result: Result<R, RuntimeError> = Err(RuntimeError::InvalidOperation(
1811 "Custom with_attribute not called".into(),
1812 ));
1813 let mut closure = |obj: &OnionObject| -> Result<(), RuntimeError> {
1814 result = f(obj);
1815 Ok(())
1816 };
1817 custom.with_attribute(key, &mut closure)?;
1818 result
1819 }
1820 _ => Err(RuntimeError::InvalidOperation(
1821 format!("with_attribute() not supported for {:?}", self).into(),
1822 )),
1823 })
1824 }
1825 pub fn apply(&self, value: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
1826 self.with_data(|obj| {
1827 value.with_data(|value| match obj {
1828 OnionObject::Tuple(tuple) => {
1829 let index = match value {
1830 OnionObject::Integer(i) => *i,
1831 _ => {
1832 return Err(RuntimeError::InvalidType(
1833 "Argument 'index' must be an integer".into(),
1834 ));
1835 }
1836 };
1837
1838 let elements = tuple.get_elements();
1839 if (index as usize) < elements.len() {
1840 Ok(OnionStaticObject::new(elements[index as usize].clone()))
1841 } else {
1842 Err(RuntimeError::InvalidOperation(
1843 "Index out of bounds for tuple".into(),
1844 ))
1845 }
1846 }
1847 OnionObject::String(s) => {
1848 let index = match value {
1849 OnionObject::Integer(i) => *i,
1850 _ => {
1851 return Err(RuntimeError::InvalidType(
1852 "Argument 'index' must be an integer".into(),
1853 ));
1854 }
1855 };
1856 if index < 0 || index >= s.len() as i64 {
1857 return Err(RuntimeError::InvalidOperation(
1858 format!("Index out of bounds for String: {}", s).into(),
1859 ));
1860 }
1861 Ok(OnionStaticObject::new(OnionObject::String(Arc::from(
1862 s.chars().nth(index as usize).unwrap().to_string(),
1863 ))))
1864 }
1865 OnionObject::Bytes(b) => {
1866 let index = match value {
1867 OnionObject::Integer(i) => *i,
1868 _ => {
1869 return Err(RuntimeError::InvalidType(
1870 "Argument 'index' must be an integer".into(),
1871 ));
1872 }
1873 };
1874 if index < 0 || index >= b.len() as i64 {
1875 return Err(RuntimeError::InvalidOperation(
1876 format!("Index out of bounds for Bytes: {:?}", b).into(),
1877 ));
1878 }
1879 Ok(OnionStaticObject::new(OnionObject::Bytes(Arc::from(vec![
1880 b[index as usize],
1881 ]))))
1882 }
1883 OnionObject::Custom(custom) => custom.apply(value),
1884 _ => Err(RuntimeError::InvalidOperation(
1885 format!("index_of() not supported for {:?}", self).into(),
1886 )),
1887 })
1888 })
1889 }
1890
1891 pub fn key_of(&self) -> Result<OnionStaticObject, RuntimeError> {
1892 self.with_data(|obj| match obj {
1893 OnionObject::Pair(pair) => Ok(pair.get_key().stabilize()),
1894 OnionObject::Lambda(lambda) => Ok(lambda.0.get_parameter().to_onion()),
1895 OnionObject::LazySet(set) => Ok(set.get_container().stabilize()),
1896 OnionObject::Custom(custom) => custom.key_of(),
1897 _ => Err(RuntimeError::InvalidOperation(
1898 format!("key_of() not supported for {:?}", obj).into(),
1899 )),
1900 })
1901 }
1902
1903 pub fn value_of(&self) -> Result<OnionStaticObject, RuntimeError> {
1904 self.with_data(|obj| match obj {
1905 OnionObject::Pair(pair) => Ok(pair.get_value().stabilize()),
1906 OnionObject::LazySet(set) => Ok(set.get_filter().stabilize()),
1907 OnionObject::Undefined(s) => Ok(OnionStaticObject::new(OnionObject::String(
1908 Arc::from(s.as_ref().map(|o| o.as_ref()).unwrap_or_else(|| "")),
1909 ))),
1910 OnionObject::Custom(custom) => custom.value_of(),
1911 _ => Err(RuntimeError::InvalidOperation(
1912 format!("value_of() not supported for {:?}", obj).into(),
1913 )),
1914 })
1915 }
1916
1917 pub fn type_of(&self) -> Result<String, RuntimeError> {
1918 self.with_data(|obj| match obj {
1919 OnionObject::Integer(_) => Ok("Integer".to_string()),
1920 OnionObject::Float(_) => Ok("Float".to_string()),
1921 OnionObject::String(_) => Ok("String".to_string()),
1922 OnionObject::Bytes(_) => Ok("Bytes".to_string()),
1923 OnionObject::Boolean(_) => Ok("Boolean".to_string()),
1924 OnionObject::Null => Ok("Null".to_string()),
1925 OnionObject::Undefined(_) => Ok("Undefined".to_string()),
1926 OnionObject::Tuple(_) => Ok("Tuple".to_string()),
1927 OnionObject::Pair(_) => Ok("Pair".to_string()),
1928 OnionObject::LazySet(_) => Ok("LazySet".to_string()),
1929 OnionObject::InstructionPackage(_) => Ok("InstructionPackage".to_string()),
1930 OnionObject::Lambda(_) => Ok("Lambda".to_string()),
1931 OnionObject::Custom(custom) => custom.type_of(),
1932 _ => Err(RuntimeError::InvalidOperation(
1933 format!("type_of() not supported for {:?}", obj).into(),
1934 )),
1935 })
1936 }
1937
1938 #[inline(always)]
1939 pub fn copy(&self) -> Result<OnionStaticObject, RuntimeError> {
1940 self.with_data(|obj| Ok(obj.stabilize()))
1941 }
1942}
1943
1944#[derive(Clone)]
1945pub enum GCArcStorage {
1946 None,
1947 Single(GCArc<OnionObjectCell>),
1948 Multiple(Arc<Vec<GCArc<OnionObjectCell>>>),
1949}
1950
1951#[derive(Clone)]
1963pub struct OnionStaticObject {
1964 pub(crate) _arcs: GCArcStorage,
1965 pub(crate) obj: OnionObject,
1966}
1967
1968impl Default for OnionStaticObject {
1969 fn default() -> Self {
1970 OnionStaticObject {
1971 obj: OnionObject::Undefined(None),
1972 _arcs: GCArcStorage::None,
1973 }
1974 }
1975}
1976
1977impl Debug for OnionStaticObject {
1978 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1979 write!(f, "OnionStaticObject({:?})", self.obj)
1980 }
1981}
1982
1983impl Display for OnionStaticObject {
1984 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1985 write!(f, "OnionStaticObject({:?})", self.obj)
1986 }
1987}
1988
1989impl OnionStaticObject {
1990 #[inline(always)]
1991 pub fn new(obj: OnionObject) -> Self {
1992 let arcs = match &obj {
1993 OnionObject::Mut(obj) => match obj.upgrade() {
1994 None => GCArcStorage::None,
1995 Some(arc) => GCArcStorage::Single(arc),
1996 },
1997 OnionObject::Boolean(_)
1998 | OnionObject::Integer(_)
1999 | OnionObject::Float(_)
2000 | OnionObject::String(_)
2001 | OnionObject::Bytes(_)
2002 | OnionObject::Null
2003 | OnionObject::Undefined(_)
2004 | OnionObject::Range(_, _)
2005 | OnionObject::InstructionPackage(_) => GCArcStorage::None,
2006 _ => {
2007 let mut arcs = vec![];
2008 obj.upgrade(&mut arcs);
2009 GCArcStorage::Multiple(Arc::new(arcs))
2010 }
2011 };
2012 OnionStaticObject {
2013 obj: obj,
2014 _arcs: arcs,
2015 }
2016 }
2017
2018 #[inline(always)]
2019 pub fn weak(&self) -> &OnionObject {
2020 &self.obj
2021 }
2022
2023 #[inline(always)]
2024 pub fn mutablize(self, gc: &mut GC<OnionObjectCell>) -> OnionStaticObject {
2027 match self.weak() {
2028 OnionObject::Mut(_) => self,
2029 v => v.clone().mutablize(gc),
2030 }
2031 }
2032
2033 #[inline(always)]
2034 pub fn immutablize(self) -> Result<OnionStaticObject, RuntimeError> {
2037 match self.weak() {
2038 OnionObject::Mut(v) => match v.upgrade() {
2039 None => Err(RuntimeError::BrokenReference),
2040 Some(arc) => match arc.as_ref().0.read() {
2041 Ok(data) => Ok(OnionStaticObject::new(data.clone())),
2042 Err(_) => Err(RuntimeError::BrokenReference),
2043 },
2044 },
2045 _ => Ok(self),
2046 }
2047 }
2048}
2049
2050#[macro_export]
2051macro_rules! unwrap_object {
2052 ($obj:expr, $variant:path) => {
2053 match $obj {
2054 $variant(o) => Ok(o),
2055 _ => Err(RuntimeError::InvalidType(
2056 format!("Expected {}, found {:?}", stringify!($variant), $obj).into(),
2057 )),
2058 }
2059 };
2060}
2061
2062#[cfg(test)]
2063mod tests {
2064 use super::*;
2065 use std::time::Instant;
2066
2067 #[test]
2068 fn test_detailed_memory_sizes() {
2069 println!("详细内存分析:");
2070 println!(
2071 "OnionObjectCell: {} bytes",
2072 std::mem::size_of::<OnionObjectCell>()
2073 );
2074 println!("OnionObject: {} bytes", std::mem::size_of::<OnionObject>());
2075 println!(
2076 "OnionStaticObject: {} bytes",
2077 std::mem::size_of::<OnionStaticObject>()
2078 );
2079 println!(
2080 "GCArcStorage: {} bytes",
2081 std::mem::size_of::<GCArcStorage>()
2082 );
2083 println!(
2084 "GCArc<OnionObjectCell>: {} bytes",
2085 std::mem::size_of::<GCArc<OnionObjectCell>>()
2086 );
2087 println!("Arc<String>: {} bytes", std::mem::size_of::<Arc<String>>());
2088 println!(
2089 "Arc<Vec<u8>>: {} bytes",
2090 std::mem::size_of::<Arc<Vec<u8>>>()
2091 );
2092 println!(
2093 "GCArcWeak<OnionObjectCell>: {} bytes",
2094 std::mem::size_of::<GCArcWeak<OnionObjectCell>>()
2095 );
2096 println!("OnionTuple: {} bytes", std::mem::size_of::<OnionTuple>());
2097 println!("OnionPair: {} bytes", std::mem::size_of::<OnionPair>());
2098 println!(
2099 "OnionLazySet: {} bytes",
2100 std::mem::size_of::<OnionLazySet>()
2101 );
2102 }
2103
2104 #[test]
2105 fn benchmark_realistic_vm_operations() {
2106 println!("真实VM操作性能测试 (使用OnionStaticObject + clone):");
2107
2108 let start = Instant::now();
2110 let mut result_sum = 0i64;
2111
2112 for i in 0..5_000_000 {
2113 let obj1 = OnionObject::Integer(i).stabilize();
2115 let obj2 = OnionObject::Integer(i + 1).stabilize();
2116
2117 let result = obj1.weak().with_data(|data1| {
2119 obj2.weak().with_data(|data2| {
2120 match (data1, data2) {
2122 (OnionObject::Integer(a), OnionObject::Integer(b)) => {
2123 Ok(OnionObject::Integer(a + b).stabilize())
2124 }
2125 _ => Err(RuntimeError::InvalidOperation("Type error".into())),
2126 }
2127 })
2128 });
2129
2130 if let Ok(sum) = result {
2131 if let Ok(val) = sum.weak().with_data(|data| match data {
2133 OnionObject::Integer(v) => Ok(*v),
2134 _ => Err(RuntimeError::InvalidType("Not integer".into())),
2135 }) {
2136 result_sum += val;
2137 }
2138 }
2139 }
2140
2141 let duration = start.elapsed();
2142 println!("500万次VM风格整数运算: {:.2}s", duration.as_secs_f64());
2143 println!("每秒操作数: {:.0}", 5_000_000.0 / duration.as_secs_f64());
2144 println!("结果校验: {}", result_sum);
2145 }
2146
2147 #[test]
2148 fn benchmark_vm_style_arithmetic() {
2149 println!("VM风格算术运算性能测试:");
2150
2151 let start = Instant::now();
2152 let mut final_result = 0i64;
2153
2154 for i in 0..2_000_000 {
2155 let left = OnionObject::Integer(i).stabilize();
2157 let right = OnionObject::Integer(i + 1).stabilize();
2158
2159 if let Ok(result) = left
2161 .weak()
2162 .with_data(|l_data| right.weak().with_data(|r_data| l_data.binary_add(r_data)))
2163 {
2164 let multiplier = OnionObject::Integer(2).stabilize();
2166 if let Ok(mul_result) = result.weak().with_data(|add_data| {
2167 multiplier
2168 .weak()
2169 .with_data(|mul_data| add_data.binary_mul(mul_data))
2170 }) {
2171 if let Ok(val) = mul_result.weak().with_data(|data| data.to_integer()) {
2173 final_result += val;
2174 }
2175 }
2176 }
2177 }
2178
2179 let duration = start.elapsed();
2180 println!("200万次复合运算: {:.2}s", duration.as_secs_f64());
2181 println!("每秒操作数: {:.0}", 2_000_000.0 / duration.as_secs_f64());
2182 println!("最终结果: {}", final_result);
2183 }
2184
2185 #[test]
2186 fn benchmark_object_creation_overhead() {
2187 println!("对象创建开销测试:");
2188
2189 let start = Instant::now();
2191 let mut objects = Vec::with_capacity(1_000_000);
2192
2193 for i in 0..1_000_000 {
2194 let obj = OnionObject::Integer(i).stabilize();
2195 objects.push(obj);
2196 }
2197
2198 let creation_time = start.elapsed();
2199 println!(
2200 "100万个OnionStaticObject创建: {:.2}s",
2201 creation_time.as_secs_f64()
2202 );
2203
2204 let start = Instant::now();
2206 let mut sum = 0i64;
2207
2208 for obj in &objects {
2209 if let Ok(val) = obj.weak().with_data(|data| data.to_integer()) {
2210 sum += val;
2211 }
2212 }
2213
2214 let access_time = start.elapsed();
2215 println!("100万次对象访问: {:.2}s", access_time.as_secs_f64());
2216 println!("访问校验和: {}", sum);
2217
2218 let start = Instant::now();
2220 let mut cloned_objects = Vec::with_capacity(objects.len());
2221
2222 for obj in &objects[..100_000] {
2223 cloned_objects.push(obj.clone());
2225 }
2226
2227 let clone_time = start.elapsed();
2228 println!("10万个对象克隆: {:.2}s", clone_time.as_secs_f64());
2229 }
2230
2231 #[test]
2232 fn benchmark_string_operations_realistic() {
2233 println!("真实字符串操作性能测试:");
2234
2235 let start = Instant::now();
2236 let mut total_length = 0usize;
2237
2238 for i in 0..500_000 {
2239 let str_obj = OnionObject::String(Arc::from(format!("string_{}", i))).stabilize();
2241
2242 if let Ok(len_obj) = str_obj.weak().with_data(|data| data.len()) {
2244 if let Ok(length) = len_obj.weak().with_data(|data| data.to_integer()) {
2245 total_length += length as usize;
2246 }
2247 }
2248
2249 let suffix = OnionObject::String(Arc::from("_suffix".to_string())).stabilize();
2251 if let Ok(concat_result) = str_obj.weak().with_data(|str_data| {
2252 suffix
2253 .weak()
2254 .with_data(|suffix_data| str_data.binary_add(suffix_data))
2255 }) {
2256 if let Ok(concat_str) = concat_result
2258 .weak()
2259 .with_data(|data| data.to_string(&mut vec![]))
2260 {
2261 total_length += concat_str.len();
2262 }
2263 }
2264 }
2265
2266 let duration = start.elapsed();
2267 println!("50万次字符串操作: {:.2}s", duration.as_secs_f64());
2268 println!("每秒操作数: {:.0}", 500_000.0 / duration.as_secs_f64());
2269 println!("总字符串长度: {}", total_length);
2270 }
2271
2272 #[test]
2273 fn benchmark_refcell_overhead() {
2274 println!("RefCell开销分析:");
2275
2276 let direct_integers: Vec<i64> = (0..1_000_000).collect();
2278 let wrapped_integers: Vec<OnionStaticObject> = (0..1_000_000)
2279 .map(|i| OnionObject::Integer(i).stabilize())
2280 .collect();
2281
2282 let start = Instant::now();
2284 let mut sum1 = 0i64;
2285 for &val in &direct_integers {
2286 sum1 += val * 2;
2287 }
2288 let direct_time = start.elapsed();
2289
2290 let start = Instant::now();
2292 let mut sum2 = 0i64;
2293 for obj in &wrapped_integers {
2294 if let Ok(val) = obj.weak().with_data(|data| match data {
2295 OnionObject::Integer(i) => Ok(*i),
2296 _ => Err(RuntimeError::InvalidType("Not integer".into())),
2297 }) {
2298 sum2 += val * 2;
2299 }
2300 }
2301 let refcell_time = start.elapsed();
2302
2303 println!("直接访问100万个i64: {:.2}s", direct_time.as_secs_f64());
2304 println!(
2305 "RefCell访问100万个OnionObject: {:.2}s",
2306 refcell_time.as_secs_f64()
2307 );
2308 println!(
2309 "RefCell开销倍数: {:.1}x",
2310 refcell_time.as_secs_f64() / direct_time.as_secs_f64()
2311 );
2312 println!("校验: {} vs {}", sum1, sum2);
2313 }
2314}