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