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::lambda::runnable::RuntimeError;
16
17use super::{
18 lambda::{
19 definition::OnionLambdaDefinition, vm_instructions::instruction_set::VMInstructionPackage,
20 },
21 lazy_set::OnionLazySet,
22 named::OnionNamed,
23 pair::OnionPair,
24 tuple::OnionTuple,
25};
26
27pub struct OnionObjectCell(pub RwLock<OnionObject>);
29
30impl OnionObjectCell {
31 #[inline(always)]
32 pub fn with_data<T, F>(&self, f: F) -> Result<T, RuntimeError>
33 where
34 F: FnOnce(&OnionObject) -> Result<T, RuntimeError>,
35 {
36 self.0
37 .read()
38 .map_err(|_| {
39 RuntimeError::BorrowError(
40 "Failed to borrow OnionObjectCell at `with_data`"
41 .to_string()
42 .into(),
43 )
44 })?
45 .with_data(f)
46 }
47 #[inline(always)]
48 pub fn with_data_mut<T, F>(&self, f: F) -> Result<T, RuntimeError>
49 where
50 F: FnOnce(&mut OnionObject) -> Result<T, RuntimeError>,
51 {
52 self.0
53 .write()
54 .map_err(|_| {
55 RuntimeError::BorrowError(
56 "Failed to borrow OnionObjectCell at `with_data_mut`"
57 .to_string()
58 .into(),
59 )
60 })?
61 .with_data_mut(f)
62 }
63
64 #[inline(always)]
65 pub fn with_data_ref_mut<T, F>(&self, f: F) -> Result<T, RuntimeError>
66 where
67 F: FnOnce(&mut OnionObject) -> Result<T, RuntimeError>,
68 {
69 self.0
70 .write()
71 .map_err(|_| {
72 RuntimeError::BorrowError(
73 "Failed to borrow OnionObjectCell at `with_data_ref_mut`"
74 .to_string()
75 .into(),
76 )
77 })?
78 .with_data_ref_mut(f)
79 }
80
81 #[inline(always)]
82 pub fn with_attribute<T, F>(&self, key: &OnionObject, f: &F) -> Result<T, RuntimeError>
83 where
84 F: Fn(&OnionObject) -> Result<T, RuntimeError>,
85 {
86 self.0
87 .read()
88 .map_err(|_| {
89 RuntimeError::BorrowError(
90 "Failed to borrow OnionObjectCell at `with_attribute`"
91 .to_string()
92 .into(),
93 )
94 })?
95 .with_attribute(key, f)
96 }
97
98 #[inline(always)]
99 pub fn upgrade(&self, collected: &mut Vec<GCArc<OnionObjectCell>>) {
100 match self.0.read() {
101 Ok(obj) => obj.upgrade(collected),
102 Err(_) => {
103 }
106 }
107 }
108
109 #[inline(always)]
110 pub fn stabilize(self) -> OnionStaticObject {
111 OnionStaticObject::new(self.try_borrow().unwrap().clone())
112 }
113
114 #[inline(always)]
115 pub fn equals(&self, other: &Self) -> Result<bool, RuntimeError> {
116 self.with_data(|obj| other.with_data(|other_obj| obj.equals(other_obj)))
117 }
118
119 #[inline(always)]
120 pub fn repr(&self, ptrs: &Vec<*const OnionObject>) -> Result<String, RuntimeError> {
121 self.with_data(|obj| obj.repr(ptrs))
122 }
123
124 #[inline(always)]
125 pub fn try_borrow(&self) -> Result<RwLockReadGuard<OnionObject>, RuntimeError> {
126 self.0.read().map_err(|_| {
127 RuntimeError::BorrowError(
128 "Failed to borrow OnionObjectCell at `try_borrow`"
129 .to_string()
130 .into(),
131 )
132 })
133 }
134 #[inline(always)]
135 pub fn try_borrow_mut(&self) -> Result<RwLockWriteGuard<OnionObject>, RuntimeError> {
136 self.0.write().map_err(|_| {
137 RuntimeError::BorrowError(
138 "Failed to borrow OnionObjectCell at `try_borrow_mut`"
139 .to_string()
140 .into(),
141 )
142 })
143 }
144}
145
146impl std::ops::Deref for OnionObjectCell {
147 type Target = RwLock<OnionObject>;
148
149 fn deref(&self) -> &Self::Target {
150 &self.0
151 }
152}
153
154impl std::ops::DerefMut for OnionObjectCell {
155 fn deref_mut(&mut self) -> &mut Self::Target {
156 &mut self.0
157 }
158}
159
160impl From<RwLock<OnionObject>> for OnionObjectCell {
161 fn from(cell: RwLock<OnionObject>) -> Self {
162 OnionObjectCell(cell)
163 }
164}
165
166impl From<OnionObject> for OnionObjectCell {
167 fn from(obj: OnionObject) -> Self {
168 OnionObjectCell(RwLock::new(obj))
169 }
170}
171
172impl GCTraceable<OnionObjectCell> for OnionObjectCell {
173 fn collect(&self, queue: &mut VecDeque<GCArcWeak<OnionObjectCell>>) {
174 if let Ok(obj) = self.0.read() {
175 obj.collect(queue);
176 }
177 }
178}
179
180impl Debug for OnionObjectCell {
181 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
182 write!(f, "{:?}", self.0.read())
183 }
184}
185
186impl Display for OnionObjectCell {
187 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
188 write!(f, "{:?}", self.0.read())
189 }
190}
191
192#[derive(Clone)]
193pub enum OnionObject {
198 Integer(i64),
200 Float(f64),
201 String(Arc<String>),
202 Bytes(Arc<Vec<u8>>),
203 Boolean(bool),
204 Range(i64, i64),
205 Null,
206 Undefined(Option<Arc<String>>),
207 InstructionPackage(Arc<VMInstructionPackage>),
208
209 Tuple(Arc<OnionTuple>),
211 Pair(Arc<OnionPair>),
212 Named(Arc<OnionNamed>),
213 LazySet(Arc<OnionLazySet>),
214 Lambda(Arc<OnionLambdaDefinition>),
215
216 Custom(Arc<dyn OnionObjectExt>),
217 Mut(GCArcWeak<OnionObjectCell>),
219}
220
221pub trait OnionObjectExt: GCTraceable<OnionObjectCell> + Debug + Send + Sync + 'static {
222 fn as_any(&self) -> &dyn std::any::Any;
224
225 fn upgrade(&self, collected: &mut Vec<GCArc<OnionObjectCell>>);
227
228 fn reconstruct_container(&self) -> Result<OnionObject, RuntimeError>;
229
230 fn to_integer(&self) -> Result<i64, RuntimeError> {
232 Err(RuntimeError::InvalidType(
233 format!("Cannot convert {:?} to Integer", self).into(),
234 ))
235 }
236 fn to_float(&self) -> Result<f64, RuntimeError> {
237 Err(RuntimeError::InvalidType(
238 format!("Cannot convert {:?} to Float", self).into(),
239 ))
240 }
241 #[allow(unused_variables)]
242 fn to_string(&self, ptrs: &Vec<*const OnionObject>) -> Result<String, RuntimeError> {
243 Err(RuntimeError::InvalidType(
244 format!("Cannot convert {:?} to String", self).into(),
245 ))
246 }
247 fn to_bytes(&self) -> Result<Vec<u8>, RuntimeError> {
248 Err(RuntimeError::InvalidType(
249 format!("Cannot convert {:?} to Bytes", self).into(),
250 ))
251 }
252 fn to_boolean(&self) -> Result<bool, RuntimeError> {
253 Err(RuntimeError::InvalidType(
254 format!("Cannot convert {:?} to Boolean", self).into(),
255 ))
256 }
257 #[allow(unused_variables)]
258 fn repr(&self, ptrs: &Vec<*const OnionObject>) -> Result<String, RuntimeError> {
259 Ok(format!("{:?}", self))
260 }
261 fn type_of(&self) -> Result<String, RuntimeError> {
262 Err(RuntimeError::InvalidType(
263 format!("Cannot get type of {:?}", self).into(),
264 ))
265 }
266
267 fn len(&self) -> Result<OnionStaticObject, RuntimeError> {
269 Err(RuntimeError::InvalidOperation(
270 format!("len() not supported for {:?}", self).into(),
271 ))
272 }
273 fn contains(&self, other: &OnionObject) -> Result<bool, RuntimeError> {
274 Err(RuntimeError::InvalidOperation(
275 format!("contains() not supported for {:?} and {:?}", self, other).into(),
276 ))
277 }
278 fn at(&self, index: i64) -> Result<OnionStaticObject, RuntimeError> {
279 Err(RuntimeError::InvalidOperation(
280 format!("at() not supported for {:?} with index {}", self, index).into(),
281 ))
282 }
283
284 fn key_of(&self) -> Result<OnionStaticObject, RuntimeError> {
286 Err(RuntimeError::InvalidOperation(
287 format!("key_of() not supported for {:?}", self).into(),
288 ))
289 }
290 fn value_of(&self) -> Result<OnionStaticObject, RuntimeError> {
291 Err(RuntimeError::InvalidOperation(
292 format!("value_of() not supported for {:?}", self).into(),
293 ))
294 }
295 #[allow(unused_variables)]
296 fn with_attribute(
297 &self,
298 key: &OnionObject,
299 f: &mut dyn FnMut(&OnionObject) -> Result<(), RuntimeError>,
300 ) -> Result<(), RuntimeError> {
301 Err(RuntimeError::InvalidOperation(
302 format!(
303 "with_attribute() not supported for {:?} with key {:?}",
304 self, key
305 )
306 .into(),
307 ))
308 }
309
310 fn equals(&self, other: &OnionObject) -> Result<bool, RuntimeError>;
312 fn is_same(&self, other: &OnionObject) -> Result<bool, RuntimeError>;
313 fn binary_eq(&self, other: &OnionObject) -> Result<bool, RuntimeError> {
314 Err(RuntimeError::InvalidOperation(
315 format!("binary_eq() not supported for {:?} and {:?}", self, other).into(),
316 ))
317 }
318 fn binary_lt(&self, other: &OnionObject) -> Result<bool, RuntimeError> {
319 Err(RuntimeError::InvalidOperation(
320 format!("binary_lt() not supported for {:?} and {:?}", self, other).into(),
321 ))
322 }
323 fn binary_gt(&self, other: &OnionObject) -> Result<bool, RuntimeError> {
324 Err(RuntimeError::InvalidOperation(
325 format!("binary_gt() not supported for {:?} and {:?}", self, other).into(),
326 ))
327 }
328
329 fn binary_add(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
331 Err(RuntimeError::InvalidOperation(
332 format!("binary_add() not supported for {:?} and {:?}", self, other).into(),
333 ))
334 }
335 fn binary_sub(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
336 Err(RuntimeError::InvalidOperation(
337 format!("binary_sub() not supported for {:?} and {:?}", self, other).into(),
338 ))
339 }
340 fn binary_mul(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
341 Err(RuntimeError::InvalidOperation(
342 format!("binary_mul() not supported for {:?} and {:?}", self, other).into(),
343 ))
344 }
345 fn binary_div(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
346 Err(RuntimeError::InvalidOperation(
347 format!("binary_div() not supported for {:?} and {:?}", self, other).into(),
348 ))
349 }
350 fn binary_mod(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
351 Err(RuntimeError::InvalidOperation(
352 format!("binary_mod() not supported for {:?} and {:?}", self, other).into(),
353 ))
354 }
355 fn binary_pow(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
356 Err(RuntimeError::InvalidOperation(
357 format!("binary_pow() not supported for {:?} and {:?}", self, other).into(),
358 ))
359 }
360
361 fn binary_and(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
363 Err(RuntimeError::InvalidOperation(
364 format!("binary_and() not supported for {:?} and {:?}", self, other).into(),
365 ))
366 }
367 fn binary_or(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
368 Err(RuntimeError::InvalidOperation(
369 format!("binary_or() not supported for {:?} and {:?}", self, other).into(),
370 ))
371 }
372 fn binary_xor(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
373 Err(RuntimeError::InvalidOperation(
374 format!("binary_xor() not supported for {:?} and {:?}", self, other).into(),
375 ))
376 }
377
378 fn binary_shl(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
380 Err(RuntimeError::InvalidOperation(
381 format!("binary_shl() not supported for {:?} and {:?}", self, other).into(),
382 ))
383 }
384 fn binary_shr(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
385 Err(RuntimeError::InvalidOperation(
386 format!("binary_shr() not supported for {:?} and {:?}", self, other).into(),
387 ))
388 }
389
390 fn unary_neg(&self) -> Result<OnionStaticObject, RuntimeError> {
392 Err(RuntimeError::InvalidOperation(
393 format!("unary_neg() not supported for {:?}", self).into(),
394 ))
395 }
396 fn unary_plus(&self) -> Result<OnionStaticObject, RuntimeError> {
397 Err(RuntimeError::InvalidOperation(
398 format!("unary_plus() not supported for {:?}", self).into(),
399 ))
400 }
401 fn unary_not(&self) -> Result<OnionStaticObject, RuntimeError> {
402 Err(RuntimeError::InvalidOperation(
403 format!("unary_not() not supported for {:?}", self).into(),
404 ))
405 }
406}
407
408impl Debug for OnionObject {
409 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
410 write!(
412 f,
413 "{}",
414 self.repr(&vec![])
415 .unwrap_or_else(|_| "BrokenReference".to_string())
416 )
417 }
418}
419
420impl GCTraceable<OnionObjectCell> for OnionObject {
421 fn collect(&self, queue: &mut VecDeque<GCArcWeak<OnionObjectCell>>) {
422 match self {
423 OnionObject::Mut(weak) => {
424 queue.push_back(weak.clone());
425 }
426 OnionObject::Tuple(tuple) => tuple.collect(queue),
427 OnionObject::Pair(pair) => pair.collect(queue),
428 OnionObject::Named(named) => named.collect(queue),
429 OnionObject::LazySet(lazy_set) => lazy_set.collect(queue),
430 OnionObject::Lambda(lambda) => lambda.collect(queue),
431 OnionObject::Custom(custom) => custom.collect(queue),
432
433 _ => {}
434 }
435 }
436}
437impl OnionObject {
438 pub fn upgrade(&self, collected: &mut Vec<GCArc<OnionObjectCell>>) {
439 match self {
440 OnionObject::Mut(weak) => {
441 if let Some(strong) = weak.upgrade() {
442 collected.push(strong);
443 }
444 }
445 OnionObject::Tuple(tuple) => tuple.upgrade(collected),
446 OnionObject::Pair(pair) => pair.upgrade(collected),
447 OnionObject::Named(named) => named.upgrade(collected),
448 OnionObject::LazySet(lazy_set) => lazy_set.upgrade(collected),
449 OnionObject::Lambda(lambda) => lambda.upgrade(collected),
450 OnionObject::Custom(custom) => custom.upgrade(collected),
451 _ => {}
452 }
453 }
454
455 #[inline(always)]
456 pub fn to_cell(self) -> OnionObjectCell {
457 OnionObjectCell(RwLock::new(self))
458 }
459
460 #[inline(always)]
461 pub fn stabilize(&self) -> OnionStaticObject {
462 OnionStaticObject::new(self.clone())
463 }
464
465 #[inline(always)]
466 pub fn consume_and_stabilize(self) -> OnionStaticObject {
467 OnionStaticObject::new(self)
468 }
469 pub fn len(&self) -> Result<OnionStaticObject, RuntimeError> {
470 self.with_data(|obj| match obj {
471 OnionObject::Tuple(tuple) => tuple.len(),
472 OnionObject::String(s) => {
473 Ok(OnionStaticObject::new(OnionObject::Integer(s.len() as i64)))
474 }
475 OnionObject::Bytes(b) => {
476 Ok(OnionStaticObject::new(OnionObject::Integer(b.len() as i64)))
477 }
478 OnionObject::Range(start, end) => Ok(OnionStaticObject::new(OnionObject::Integer(
479 (end - start) as i64,
480 ))),
481 OnionObject::Custom(custom) => custom.len(),
482 _ => Err(RuntimeError::InvalidOperation(
483 format!("len() not supported for {:?}", self).into(),
484 )),
485 })
486 }
487
488 pub fn contains(&self, other: &OnionObject) -> Result<bool, RuntimeError> {
489 self.with_data(|obj| {
490 other.with_data(|other_obj| match (obj, other_obj) {
491 (OnionObject::Tuple(tuple), _) => tuple.contains(other_obj),
492 (OnionObject::String(s), OnionObject::String(other_s)) => {
493 Ok(s.contains(other_s.as_ref()))
494 }
495 (OnionObject::Bytes(b), OnionObject::Bytes(other_b)) => Ok(b
496 .windows(other_b.len())
497 .any(|window| window == other_b.as_slice())),
498 (OnionObject::Range(l, r), OnionObject::Integer(i)) => Ok(*i >= *l && *i < *r),
499 (OnionObject::Range(start, end), OnionObject::Float(f)) => {
500 Ok(*f >= *start as f64 && *f < *end as f64)
501 }
502 (OnionObject::Range(start, end), OnionObject::Range(other_start, other_end)) => {
503 Ok(*other_start >= *start && *other_end <= *end)
504 }
505 (OnionObject::Custom(custom), _) => custom.contains(other_obj),
506 _ => Err(RuntimeError::InvalidOperation(
507 format!("contains() not supported for {:?}", obj).into(),
508 )),
509 })
510 })
511 }
512
513 pub fn clone_value(&self) -> Result<OnionStaticObject, RuntimeError> {
517 self.with_data(|obj| Ok(obj.reconstruct_container()?.consume_and_stabilize()))
518 }
519
520 pub fn with_data<T, F>(&self, f: F) -> Result<T, RuntimeError>
524 where
525 F: FnOnce(&OnionObject) -> Result<T, RuntimeError>,
526 {
527 match self {
528 OnionObject::Mut(weak) => {
529 if let Some(strong) = weak.upgrade() {
530 strong.as_ref().with_data(f)
532 } else {
533 Err(RuntimeError::BrokenReference)
534 }
535 }
536 _ => f(self),
537 }
538 }
539
540 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)
552 } else {
553 Err(RuntimeError::BrokenReference)
554 }
555 }
556 _ => f(self),
557 }
558 }
559 pub fn assign(&self, other: &OnionObject) -> Result<(), RuntimeError> {
561 let OnionObject::Mut(weak) = self else {
564 return Err(RuntimeError::InvalidOperation(
565 format!("Cannot assign to non-mutable object: {:?}", self).into(),
566 ));
567 };
568 match weak.upgrade() {
569 Some(strong) => {
570 let new_value = other.with_data(|other| other.reconstruct_container())?;
572
573 strong.as_ref().with_data_mut(|obj| {
575 *obj = new_value;
576 Ok(())
577 })
578 }
579 None => Err(RuntimeError::BrokenReference),
580 }
581 }
582 pub fn with_data_ref_mut<T, F>(&self, f: F) -> Result<T, RuntimeError>
583 where
584 F: FnOnce(&mut OnionObject) -> Result<T, RuntimeError>,
585 {
586 let OnionObject::Mut(weak) = self else {
587 return Err(RuntimeError::InvalidOperation(
588 format!("Cannot mutate non-mutable object: {:?}", self).into(),
589 ));
590 };
591 match weak.upgrade() {
592 Some(strong) => strong.as_ref().with_data_mut(f),
593 None => Err(RuntimeError::BrokenReference),
594 }
595 }
596 pub fn reconstruct_container(&self) -> Result<OnionObject, RuntimeError> {
598 match self {
599 OnionObject::Tuple(tuple) => tuple.reconstruct_container(),
600 OnionObject::Pair(pair) => pair.reconstruct_container(),
601 OnionObject::Named(named) => named.reconstruct_container(),
602 OnionObject::LazySet(lazy_set) => lazy_set.reconstruct_container(),
603 OnionObject::Lambda(lambda) => lambda.reconstruct_container(),
604 OnionObject::Custom(custom) => custom.reconstruct_container(),
605 _ => Ok(self.clone()), }
608 }
609 pub fn to_integer(&self) -> Result<i64, RuntimeError> {
610 self.with_data(|obj| match obj {
611 OnionObject::Integer(i) => Ok(*i),
612 OnionObject::Float(f) => Ok(*f as i64),
613 OnionObject::String(s) => s
614 .parse::<i64>()
615 .map_err(|e| RuntimeError::InvalidType(e.to_string().into())),
616 OnionObject::Boolean(b) => Ok(if *b { 1 } else { 0 }),
617 OnionObject::Custom(custom) => custom.to_integer(),
618 _ => Err(RuntimeError::InvalidType(
619 format!("Cannot convert {:?} to Integer", obj).into(),
620 )),
621 })
622 }
623 pub fn to_float(&self) -> Result<f64, RuntimeError> {
624 self.with_data(|obj| match obj {
625 OnionObject::Integer(i) => Ok(*i as f64),
626 OnionObject::Float(f) => Ok(*f),
627 OnionObject::String(s) => s
628 .parse::<f64>()
629 .map_err(|e| RuntimeError::InvalidType(e.to_string().into())),
630 OnionObject::Boolean(b) => Ok(if *b { 1.0 } else { 0.0 }),
631 OnionObject::Custom(custom) => custom.to_float(),
632 _ => Err(RuntimeError::InvalidType(
633 format!("Cannot convert {:?} to Float", obj).into(),
634 )),
635 })
636 }
637
638 pub fn to_string(&self, ptrs: &Vec<*const OnionObject>) -> Result<String, RuntimeError> {
639 self.with_data(|obj| {
640 for ptr in ptrs {
641 if addr_eq(obj, *ptr) {
642 return Ok("...".to_string());
643 }
644 }
645 let mut new_ptrs = ptrs.clone();
646 new_ptrs.push(obj);
647 match obj {
648 OnionObject::Integer(i) => Ok(i.to_string()),
649 OnionObject::Float(f) => Ok(f.to_string()),
650 OnionObject::String(s) => Ok(s.as_ref().clone()),
651 OnionObject::Bytes(b) => Ok(format!(
652 "$\"{}\"",
653 general_purpose::STANDARD.encode(b.as_ref())
654 )),
655 OnionObject::Boolean(b) => Ok(if *b {
656 "true".to_string()
657 } else {
658 "false".to_string()
659 }),
660 OnionObject::Null => Ok("null".to_string()),
661 OnionObject::Undefined(s) => Ok(match s {
662 Some(s) => format!("undefined({:?})", s),
663 None => "undefined".to_string(),
664 }),
665 OnionObject::Range(start, end) => Ok(format!("{}..{}", start, end)),
666 OnionObject::Tuple(tuple) => match tuple.get_elements().len() {
667 0 => Ok("()".to_string()),
668 1 => {
669 let first = tuple.get_elements().first().unwrap();
670 Ok(format!("({},)", first.repr(&new_ptrs)?))
671 }
672 _ => {
673 let elements: Result<Vec<String>, RuntimeError> = tuple
674 .get_elements()
675 .iter()
676 .map(|e| e.repr(&new_ptrs))
677 .collect();
678 Ok(format!("({})", elements?.join(", ")))
679 }
680 },
681 OnionObject::Pair(pair) => {
682 let left = pair.get_key().repr(&new_ptrs)?;
683 let right = pair.get_value().repr(&new_ptrs)?;
684 Ok(format!("{} : {}", left, right))
685 }
686 OnionObject::Named(named) => {
687 let name = named.get_key().repr(&new_ptrs)?;
688 let value = named.get_value().repr(&new_ptrs)?;
689 Ok(format!("{} => {}", name, value))
690 }
691 OnionObject::LazySet(lazy_set) => {
692 let container = lazy_set.get_container().repr(&new_ptrs)?;
693 let filter = lazy_set.get_filter().repr(&new_ptrs)?;
694 Ok(format!("[{} | {}]", container, filter))
695 }
696 OnionObject::InstructionPackage(_) => Ok("InstructionPackage(...)".to_string()),
697 OnionObject::Lambda(lambda) => {
698 let params = lambda.get_parameter().repr(&new_ptrs)?;
699 let body = lambda.get_body().to_string();
700 Ok(format!(
701 "{}::{} -> {}",
702 lambda.get_signature(),
703 params,
704 body
705 ))
706 }
707 OnionObject::Custom(custom) => custom.to_string(&new_ptrs),
708 _ => {
709 Ok(format!("{:?}", obj))
711 }
712 }
713 })
714 }
715
716 pub fn repr(&self, ptrs: &Vec<*const OnionObject>) -> Result<String, RuntimeError> {
717 self.with_data(|obj| {
718 for ptr in ptrs {
719 if addr_eq(obj, *ptr) {
720 return Ok("...".to_string());
721 }
722 }
723 let mut new_ptrs = ptrs.clone();
724 new_ptrs.push(obj);
725 match obj {
726 OnionObject::Integer(i) => Ok(format!("{}", i)),
727 OnionObject::Float(f) => Ok(format!("{}", f)),
728 OnionObject::String(s) => Ok(format!("{:?}", s)),
729 OnionObject::Bytes(b) => Ok(format!(
730 "$\"{}\"",
731 general_purpose::STANDARD.encode(b.as_ref())
732 )),
733 OnionObject::Boolean(b) => Ok(format!("{}", b)),
734 OnionObject::Null => Ok("null".to_string()),
735 OnionObject::Undefined(s) => Ok(match s {
736 Some(s) => format!("undefined({:?})", s),
737 None => "undefined".to_string(),
738 }),
739 OnionObject::Range(start, end) => Ok(format!("{}..{}", start, end)),
740 OnionObject::Tuple(tuple) => match tuple.get_elements().len() {
741 0 => Ok("()".to_string()),
742 1 => {
743 let first = tuple.get_elements().first().unwrap();
744 Ok(format!("({},)", first.repr(&new_ptrs)?))
745 }
746 _ => {
747 let elements: Result<Vec<String>, RuntimeError> = tuple
748 .get_elements()
749 .iter()
750 .map(|e| e.repr(&new_ptrs))
751 .collect();
752 Ok(format!("({})", elements?.join(", ")))
753 }
754 },
755 OnionObject::Pair(pair) => {
756 let left = pair.get_key().repr(&new_ptrs)?;
757 let right = pair.get_value().repr(&new_ptrs)?;
758 Ok(format!("{} : {}", left, right))
759 }
760 OnionObject::Named(named) => {
761 let name = named.get_key().repr(&new_ptrs)?;
762 let value = named.get_value().repr(&new_ptrs)?;
763 Ok(format!("{} => {}", name, value))
764 }
765 OnionObject::LazySet(lazy_set) => {
766 let container = lazy_set.get_container().repr(&new_ptrs)?;
767 let filter = lazy_set.get_filter().repr(&new_ptrs)?;
768 Ok(format!("[{} | {}]", container, filter))
769 }
770 OnionObject::InstructionPackage(_) => Ok("InstructionPackage(...)".to_string()),
771 OnionObject::Lambda(lambda) => {
772 let params = lambda.get_parameter().repr(&new_ptrs)?;
773 Ok(format!(
774 "{}::{} -> {}",
775 lambda.get_signature(),
776 params,
777 lambda.get_body()
778 ))
779 }
780 OnionObject::Mut(weak) => {
781 if let Some(strong) = weak.upgrade() {
782 let inner_repr = strong
783 .as_ref()
784 .try_borrow()
785 .map_err(|_| {
786 RuntimeError::BorrowError(
787 "Failed to borrow Mut object at `repr`".to_string().into(),
788 )
789 })?
790 .repr(&new_ptrs)?;
791 Ok(format!("mut ({})", inner_repr))
792 } else {
793 Ok("Mut(BrokenReference)".to_string())
794 }
795 }
796 OnionObject::Custom(custom) => {
797 let custom_repr = custom.repr(&new_ptrs)?;
798 Ok(format!("Custom({})", custom_repr))
799 }
800 }
801 })
802 }
803 pub fn to_bytes(&self) -> Result<Vec<u8>, RuntimeError> {
804 self.with_data(|obj| match obj {
805 OnionObject::Integer(i) => Ok(i.to_string().into_bytes()),
806 OnionObject::Float(f) => Ok(f.to_string().into_bytes()),
807 OnionObject::String(s) => Ok(s.as_bytes().to_vec()),
808 OnionObject::Bytes(b) => Ok(b.as_ref().clone()),
809 OnionObject::Boolean(b) => Ok(if *b {
810 b"true".to_vec()
811 } else {
812 b"false".to_vec()
813 }),
814 OnionObject::Custom(custom) => custom.to_bytes(),
815 _ => Err(RuntimeError::InvalidType(
816 format!("Cannot convert {:?} to Bytes", obj).into(),
817 )),
818 })
819 }
820
821 pub fn to_boolean(&self) -> Result<bool, RuntimeError> {
822 self.with_data(|obj| match obj {
823 OnionObject::Integer(i) => Ok(*i != 0),
824 OnionObject::Float(f) => Ok(*f != 0.0),
825 OnionObject::String(s) => Ok(!s.is_empty()),
826 OnionObject::Bytes(b) => Ok(!b.is_empty()),
827 OnionObject::Boolean(b) => Ok(*b),
828 OnionObject::Null => Ok(false),
829 OnionObject::Undefined(_) => Ok(false),
830 OnionObject::Custom(custom) => custom.to_boolean(),
831 _ => Err(RuntimeError::InvalidType(
832 format!("Cannot convert {:?} to Boolean", obj).into(),
833 )),
834 })
835 }
836 pub fn mutablize(self, gc: &mut GC<OnionObjectCell>) -> OnionStaticObject {
837 let arc = gc.create(OnionObjectCell::from(self));
838 OnionStaticObject {
839 obj: OnionObject::Mut(arc.as_weak()),
840 _arcs: GCArcStorage::Single(arc),
841 }
842 }
843}
844
845impl OnionObject {
846 pub fn equals(&self, other: &Self) -> Result<bool, RuntimeError> {
847 self.with_data(|left| {
848 other.with_data(|right| {
849 match (left, right) {
850 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => Ok(i1 == i2),
851 (OnionObject::Float(f1), OnionObject::Float(f2)) => Ok(f1 == f2),
852 (OnionObject::Integer(i1), OnionObject::Float(f2)) => Ok(*i1 as f64 == *f2),
853 (OnionObject::Float(f1), OnionObject::Integer(i2)) => Ok(*f1 == *i2 as f64),
854 (OnionObject::String(s1), OnionObject::String(s2)) => Ok(s1 == s2),
855 (OnionObject::Bytes(b1), OnionObject::Bytes(b2)) => Ok(b1 == b2),
856 (OnionObject::Boolean(b1), OnionObject::Boolean(b2)) => Ok(b1 == b2),
857 (OnionObject::Range(start1, end1), OnionObject::Range(start2, end2)) => {
858 Ok(start1 == start2 && end1 == end2)
859 }
860 (OnionObject::Null, OnionObject::Null) => Ok(true),
861 (OnionObject::Undefined(_), OnionObject::Undefined(_)) => Ok(true),
862 (OnionObject::Tuple(t1), _) => t1.equals(other),
863 (OnionObject::Pair(p1), _) => p1.equals(other),
864 (OnionObject::Named(n1), _) => n1.equals(other),
865 (OnionObject::Custom(c1), _) => c1.equals(other),
866
867 _ => Ok(false),
869 }
870 })
871 })
872 }
873 pub fn is_same(&self, other: &Self) -> Result<bool, RuntimeError> {
874 match (self, other) {
875 (OnionObject::Mut(weak1), OnionObject::Mut(weak2)) => {
876 if let (Some(strong1), Some(strong2)) = (weak1.upgrade(), weak2.upgrade()) {
877 Ok(addr_eq(strong1.as_ref(), strong2.as_ref()))
878 } else {
879 Ok(false)
880 }
881 }
882 (OnionObject::Custom(c1), _) => c1.is_same(other),
883 _ => self.equals(other),
884 }
885 }
886
887 pub fn binary_add(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
888 self.with_data(|obj| {
889 other.with_data(|other_obj| match (obj, other_obj) {
890 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => {
891 Ok(OnionStaticObject::new(OnionObject::Integer(i1 + i2)))
892 }
893 (OnionObject::Float(f1), OnionObject::Float(f2)) => {
894 Ok(OnionStaticObject::new(OnionObject::Float(f1 + f2)))
895 }
896 (OnionObject::Integer(i1), OnionObject::Float(f2)) => {
897 Ok(OnionStaticObject::new(OnionObject::Float(*i1 as f64 + f2)))
898 }
899 (OnionObject::Float(f1), OnionObject::Integer(i2)) => {
900 Ok(OnionStaticObject::new(OnionObject::Float(f1 + *i2 as f64)))
901 }
902 (OnionObject::String(s1), OnionObject::String(s2)) => Ok(OnionStaticObject::new(
903 OnionObject::String(Arc::new(format!("{}{}", s1, s2))),
904 )),
905 (OnionObject::Bytes(b1), OnionObject::Bytes(b2)) => {
906 let mut new_bytes = b1.as_ref().clone();
907 new_bytes.extend_from_slice(b2);
908 Ok(OnionStaticObject::new(OnionObject::Bytes(Arc::new(
909 new_bytes,
910 ))))
911 }
912 (OnionObject::Range(start1, end1), OnionObject::Range(start2, end2)) => Ok(
913 OnionStaticObject::new(OnionObject::Range(start1 + start2, end1 + end2)),
914 ),
915 (OnionObject::Tuple(t1), _) => t1.binary_add(other_obj),
916 (OnionObject::Custom(c1), _) => c1.binary_add(other_obj),
917 _ => Err(RuntimeError::InvalidOperation(
918 format!(
919 "Invalid binary add operation for {:?} and {:?}",
920 obj, other_obj
921 )
922 .into(),
923 )),
924 })
925 })
926 }
927
928 pub fn binary_sub(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
929 self.with_data(|obj| {
930 other.with_data(|other_obj| match (obj, other_obj) {
931 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => {
932 Ok(OnionStaticObject::new(OnionObject::Integer(i1 - i2)))
933 }
934 (OnionObject::Float(f1), OnionObject::Float(f2)) => {
935 Ok(OnionStaticObject::new(OnionObject::Float(f1 - f2)))
936 }
937 (OnionObject::Integer(i1), OnionObject::Float(f2)) => {
938 Ok(OnionStaticObject::new(OnionObject::Float(*i1 as f64 - f2)))
939 }
940 (OnionObject::Float(f1), OnionObject::Integer(i2)) => {
941 Ok(OnionStaticObject::new(OnionObject::Float(f1 - *i2 as f64)))
942 }
943 (OnionObject::Custom(c1), _) => c1.binary_sub(other_obj),
944 _ => Err(RuntimeError::InvalidOperation(
945 format!(
946 "Invalid binary sub operation for {:?} and {:?}",
947 obj, other_obj
948 )
949 .into(),
950 )),
951 })
952 })
953 }
954
955 pub fn binary_mul(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
956 self.with_data(|obj| {
957 other.with_data(|other_obj| match (obj, other_obj) {
958 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => {
959 Ok(OnionStaticObject::new(OnionObject::Integer(i1 * i2)))
960 }
961 (OnionObject::Float(f1), OnionObject::Float(f2)) => {
962 Ok(OnionStaticObject::new(OnionObject::Float(f1 * f2)))
963 }
964 (OnionObject::Integer(i1), OnionObject::Float(f2)) => {
965 Ok(OnionStaticObject::new(OnionObject::Float(*i1 as f64 * f2)))
966 }
967 (OnionObject::Float(f1), OnionObject::Integer(i2)) => {
968 Ok(OnionStaticObject::new(OnionObject::Float(f1 * *i2 as f64)))
969 }
970 (OnionObject::Custom(c1), _) => c1.binary_mul(other_obj),
971 _ => Err(RuntimeError::InvalidOperation(
972 format!(
973 "Invalid binary mul operation for {:?} and {:?}",
974 obj, other_obj
975 )
976 .into(),
977 )),
978 })
979 })
980 }
981
982 pub fn binary_div(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
983 self.with_data(|obj| {
984 other.with_data(|other_obj| match (obj, other_obj) {
985 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => {
986 if *i2 == 0 {
987 return Err(RuntimeError::InvalidOperation(
988 "Division by zero".to_string().into(),
989 ));
990 }
991 Ok(OnionStaticObject::new(OnionObject::Integer(i1 / i2)))
992 }
993 (OnionObject::Float(f1), OnionObject::Float(f2)) => {
994 Ok(OnionStaticObject::new(OnionObject::Float(f1 / f2)))
995 }
996 (OnionObject::Integer(i1), OnionObject::Float(f2)) => {
997 Ok(OnionStaticObject::new(OnionObject::Float(*i1 as f64 / f2)))
998 }
999 (OnionObject::Float(f1), OnionObject::Integer(i2)) => {
1000 Ok(OnionStaticObject::new(OnionObject::Float(f1 / *i2 as f64)))
1001 }
1002 (OnionObject::Custom(c1), _) => c1.binary_div(other_obj),
1003 _ => Err(RuntimeError::InvalidOperation(
1004 format!(
1005 "Invalid binary div operation for {:?} and {:?}",
1006 obj, other_obj
1007 )
1008 .into(),
1009 )),
1010 })
1011 })
1012 }
1013
1014 pub fn binary_mod(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
1015 self.with_data(|obj| {
1016 other.with_data(|other_obj| match (obj, other_obj) {
1017 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => {
1018 if *i2 == 0 {
1019 return Err(RuntimeError::InvalidOperation(
1020 "Division by zero".to_string().into(),
1021 ));
1022 }
1023 Ok(OnionStaticObject::new(OnionObject::Integer(i1 % i2)))
1024 }
1025 (OnionObject::Float(f1), OnionObject::Float(f2)) => {
1026 Ok(OnionStaticObject::new(OnionObject::Float(f1 % f2)))
1027 }
1028 (OnionObject::Integer(i1), OnionObject::Float(f2)) => {
1029 Ok(OnionStaticObject::new(OnionObject::Float(*i1 as f64 % f2)))
1030 }
1031 (OnionObject::Float(f1), OnionObject::Integer(i2)) => {
1032 Ok(OnionStaticObject::new(OnionObject::Float(f1 % *i2 as f64)))
1033 }
1034 (OnionObject::Custom(c1), _) => c1.binary_mod(other_obj),
1035 _ => Err(RuntimeError::InvalidOperation(
1036 format!(
1037 "Invalid binary mod operation for {:?} and {:?}",
1038 obj, other_obj
1039 )
1040 .into(),
1041 )),
1042 })
1043 })
1044 }
1045
1046 pub fn binary_pow(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
1047 self.with_data(|obj| {
1048 other.with_data(|other_obj| match (obj, other_obj) {
1049 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => Ok(OnionStaticObject::new(
1050 OnionObject::Integer(i1.pow(*i2 as u32)),
1051 )),
1052 (OnionObject::Float(f1), OnionObject::Float(f2)) => {
1053 Ok(OnionStaticObject::new(OnionObject::Float(f1.powf(*f2))))
1054 }
1055 (OnionObject::Integer(i1), OnionObject::Float(f2)) => Ok(OnionStaticObject::new(
1056 OnionObject::Float((*i1 as f64).powf(*f2)),
1057 )),
1058 (OnionObject::Float(f1), OnionObject::Integer(i2)) => Ok(OnionStaticObject::new(
1059 OnionObject::Float(f1.powi(*i2 as i32)),
1060 )),
1061 (OnionObject::Custom(c1), _) => c1.binary_pow(other_obj),
1062 _ => Err(RuntimeError::InvalidOperation(
1063 format!(
1064 "Invalid binary pow operation for {:?} and {:?}",
1065 obj, other_obj
1066 )
1067 .into(),
1068 )),
1069 })
1070 })
1071 }
1072
1073 pub fn binary_and(&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_and(other_obj),
1083 _ => Err(RuntimeError::InvalidOperation(
1084 format!(
1085 "Invalid binary and operation for {:?} and {:?}",
1086 obj, other_obj
1087 )
1088 .into(),
1089 )),
1090 })
1091 })
1092 }
1093
1094 pub fn binary_or(&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::Boolean(f1), OnionObject::Boolean(f2)) => {
1101 Ok(OnionStaticObject::new(OnionObject::Boolean(*f1 || *f2)))
1102 }
1103 (OnionObject::Custom(c1), _) => c1.binary_or(other_obj),
1104 _ => Err(RuntimeError::InvalidOperation(
1105 format!(
1106 "Invalid binary or operation for {:?} and {:?}",
1107 obj, other_obj
1108 )
1109 .into(),
1110 )),
1111 })
1112 })
1113 }
1114
1115 pub fn binary_xor(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
1116 self.with_data(|obj| {
1117 other.with_data(|other_obj| match (obj, other_obj) {
1118 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => {
1119 Ok(OnionStaticObject::new(OnionObject::Integer(i1 ^ i2)))
1120 }
1121 (OnionObject::Custom(c1), _) => c1.binary_xor(other_obj),
1122 _ => Err(RuntimeError::InvalidOperation(
1123 format!(
1124 "Invalid binary xor operation for {:?} and {:?}",
1125 obj, other_obj
1126 )
1127 .into(),
1128 )),
1129 })
1130 })
1131 }
1132
1133 pub fn binary_shl(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
1134 self.with_data(|obj| {
1135 other.with_data(|other_obj| match (obj, other_obj) {
1136 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => {
1137 Ok(OnionStaticObject::new(OnionObject::Integer(i1 << i2)))
1138 }
1139 (OnionObject::Custom(c1), _) => c1.binary_shl(other_obj),
1140 _ => Err(RuntimeError::InvalidOperation(
1141 format!(
1142 "Invalid binary shl operation for {:?} and {:?}",
1143 obj, other_obj
1144 )
1145 .into(),
1146 )),
1147 })
1148 })
1149 }
1150
1151 pub fn binary_shr(&self, other: &Self) -> Result<OnionStaticObject, RuntimeError> {
1152 self.with_data(|obj| {
1153 other.with_data(|other_obj| match (obj, other_obj) {
1154 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => {
1155 Ok(OnionStaticObject::new(OnionObject::Integer(i1 >> i2)))
1156 }
1157 (OnionObject::Custom(c1), _) => c1.binary_shr(other_obj),
1158 _ => Err(RuntimeError::InvalidOperation(
1159 format!(
1160 "Invalid binary shr operation for {:?} and {:?}",
1161 obj, other_obj
1162 )
1163 .into(),
1164 )),
1165 })
1166 })
1167 }
1168
1169 pub fn binary_eq(&self, other: &Self) -> Result<bool, RuntimeError> {
1170 self.equals(other)
1171 }
1172
1173 pub fn binary_lt(&self, other: &Self) -> Result<bool, RuntimeError> {
1174 self.with_data(|obj| {
1175 other.with_data(|other_obj| match (obj, other_obj) {
1176 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => Ok(i1 < i2),
1177 (OnionObject::Float(f1), OnionObject::Float(f2)) => Ok(f1 < f2),
1178 (OnionObject::Integer(i1), OnionObject::Float(f2)) => Ok((*i1 as f64) < *f2),
1179 (OnionObject::Float(f1), OnionObject::Integer(i2)) => Ok(*f1 < *i2 as f64),
1180 (OnionObject::Custom(c1), _) => c1.binary_lt(other_obj),
1181 _ => Err(RuntimeError::InvalidOperation(
1182 format!(
1183 "Invalid binary lt operation for {:?} and {:?}",
1184 obj, other_obj
1185 )
1186 .into(),
1187 )),
1188 })
1189 })
1190 }
1191
1192 pub fn binary_gt(&self, other: &Self) -> Result<bool, RuntimeError> {
1193 self.with_data(|obj| {
1194 other.with_data(|other_obj| match (obj, other_obj) {
1195 (OnionObject::Integer(i1), OnionObject::Integer(i2)) => Ok(i1 > i2),
1196 (OnionObject::Float(f1), OnionObject::Float(f2)) => Ok(f1 > f2),
1197 (OnionObject::Integer(i1), OnionObject::Float(f2)) => Ok((*i1 as f64) > *f2),
1198 (OnionObject::Float(f1), OnionObject::Integer(i2)) => Ok(*f1 > *i2 as f64),
1199 (OnionObject::Custom(c1), _) => c1.binary_gt(other_obj),
1200 _ => Err(RuntimeError::InvalidOperation(
1201 format!(
1202 "Invalid binary gt operation for {:?} and {:?}",
1203 obj, other_obj
1204 )
1205 .into(),
1206 )),
1207 })
1208 })
1209 }
1210
1211 pub fn unary_neg(&self) -> Result<OnionStaticObject, RuntimeError> {
1212 self.with_data(|obj| match obj {
1213 OnionObject::Integer(i) => Ok(OnionStaticObject::new(OnionObject::Integer(-i))),
1214 OnionObject::Float(f) => Ok(OnionStaticObject::new(OnionObject::Float(-f))),
1215 OnionObject::Custom(custom) => custom.unary_neg(),
1216 _ => Err(RuntimeError::InvalidOperation(
1217 format!("Invalid unary neg operation for {:?}", obj).into(),
1218 )),
1219 })
1220 }
1221
1222 pub fn unary_plus(&self) -> Result<OnionStaticObject, RuntimeError> {
1223 self.with_data(|obj| match obj {
1224 OnionObject::Integer(i) => Ok(OnionStaticObject::new(OnionObject::Integer(i.abs()))),
1225 OnionObject::Float(f) => Ok(OnionStaticObject::new(OnionObject::Float(f.abs()))),
1226 OnionObject::Custom(custom) => custom.unary_plus(),
1227 _ => Err(RuntimeError::InvalidOperation(
1228 format!("Invalid unary plus operation for {:?}", obj).into(),
1229 )),
1230 })
1231 }
1232
1233 pub fn unary_not(&self) -> Result<OnionStaticObject, RuntimeError> {
1234 self.with_data(|obj| match obj {
1235 OnionObject::Boolean(b) => Ok(OnionStaticObject::new(OnionObject::Boolean(!b))),
1236 OnionObject::Integer(i) => Ok(OnionStaticObject::new(OnionObject::Integer(!i))),
1237 OnionObject::Custom(custom) => custom.unary_not(),
1238 _ => Err(RuntimeError::InvalidOperation(
1239 format!("Invalid unary not operation for {:?}", obj).into(),
1240 )),
1241 })
1242 }
1243
1244 pub fn with_attribute<F, R>(&self, key: &OnionObject, f: &F) -> Result<R, RuntimeError>
1245 where
1246 F: Fn(&OnionObject) -> Result<R, RuntimeError>,
1247 {
1248 self.with_data(|obj| match obj {
1249 OnionObject::Tuple(tuple) => tuple.with_attribute(key, f),
1250 OnionObject::Named(named) => named.with_attribute(key, f),
1251 OnionObject::Pair(pair) => pair.with_attribute(key, f),
1252 OnionObject::Lambda(lambda) => lambda.with_attribute(key, f),
1253 OnionObject::LazySet(lazy_set) => lazy_set.with_attribute(key, f),
1254 OnionObject::String(s) => {
1255 if let OnionObject::String(key_str) = key {
1256 if key_str.as_ref().eq("length") {
1257 return f(&OnionObject::Integer(s.len() as i64));
1258 }
1259 if key_str.as_ref().eq("elements") {
1260 let elements = OnionTuple::new_static_no_ref(
1261 &s.chars()
1262 .map(|c| {
1263 OnionStaticObject::new(OnionObject::String(Arc::new(
1264 c.to_string(),
1265 )))
1266 })
1267 .collect::<Vec<_>>(),
1268 );
1269 return f(elements.weak());
1270 }
1271 }
1272 Err(RuntimeError::InvalidOperation(
1273 format!("with_attribute() not supported for String: {}", s).into(),
1274 ))
1275 }
1276 OnionObject::Bytes(b) => {
1277 if let OnionObject::String(key_str) = key {
1278 if key_str.as_ref().eq("length") {
1279 return f(&OnionObject::Integer(b.len() as i64));
1280 }
1281 if key_str.as_ref().eq("elements") {
1282 let elements = OnionTuple::new_static_no_ref(
1283 &b.iter()
1284 .map(|byte| {
1285 OnionStaticObject::new(OnionObject::Integer(*byte as i64))
1286 })
1287 .collect::<Vec<_>>(),
1288 );
1289 return f(elements.weak());
1290 }
1291 }
1292 Err(RuntimeError::InvalidOperation(
1293 format!("with_attribute() not supported for Bytes: {:?}", b).into(),
1294 ))
1295 }
1296 OnionObject::Range(start, end) => {
1297 if let OnionObject::String(key_str) = key {
1298 if key_str.as_ref().eq("length") {
1299 return f(&OnionObject::Integer((end - start) as i64));
1300 }
1301 if key_str.as_ref().eq("elements") {
1302 let elements = OnionTuple::new_static_no_ref(
1303 &(*start..*end)
1304 .map(|i| OnionStaticObject::new(OnionObject::Integer(i as i64)))
1305 .collect::<Vec<_>>(),
1306 );
1307 return f(elements.weak());
1308 }
1309 }
1310 Err(RuntimeError::InvalidOperation(
1311 format!(
1312 "with_attribute() not supported for Range: {}..{}",
1313 start, end
1314 )
1315 .into(),
1316 ))
1317 }
1318 OnionObject::Custom(custom) => {
1319 let mut result: Result<R, RuntimeError> = Err(RuntimeError::InvalidOperation(
1320 "Custom with_attribute not called".to_string().into(),
1321 ));
1322 let mut closure = |obj: &OnionObject| -> Result<(), RuntimeError> {
1323 result = f(obj);
1324 Ok(())
1325 };
1326 custom.with_attribute(key, &mut closure)?;
1327 result
1328 }
1329 _ => Err(RuntimeError::InvalidOperation(
1330 format!("with_attribute() not supported for {:?}", self).into(),
1331 )),
1332 })
1333 }
1334 pub fn at(&self, index: i64) -> Result<OnionStaticObject, RuntimeError> {
1335 self.with_data(|obj| match obj {
1336 OnionObject::Tuple(tuple) => tuple.at(index),
1337 OnionObject::String(s) => {
1338 if index < 0 || index >= s.len() as i64 {
1339 return Err(RuntimeError::InvalidOperation(
1340 format!("Index out of bounds for String: {}", s).into(),
1341 ));
1342 }
1343 Ok(OnionStaticObject::new(OnionObject::String(Arc::new(
1344 s.chars().nth(index as usize).unwrap().to_string(),
1345 ))))
1346 }
1347 OnionObject::Bytes(b) => {
1348 if index < 0 || index >= b.len() as i64 {
1349 return Err(RuntimeError::InvalidOperation(
1350 format!("Index out of bounds for Bytes: {:?}", b).into(),
1351 ));
1352 }
1353 Ok(OnionStaticObject::new(OnionObject::Bytes(Arc::new(vec![
1354 b[index as usize],
1355 ]))))
1356 }
1357 OnionObject::Custom(custom) => custom.at(index),
1358 _ => Err(RuntimeError::InvalidOperation(
1359 format!("index_of() not supported for {:?}", self).into(),
1360 )),
1361 })
1362 }
1363
1364 pub fn key_of(&self) -> Result<OnionStaticObject, RuntimeError> {
1365 self.with_data(|obj| match obj {
1366 OnionObject::Named(named) => Ok(named.get_key().stabilize()),
1367 OnionObject::Pair(pair) => Ok(pair.get_key().stabilize()),
1368 OnionObject::Custom(custom) => custom.key_of(),
1369 _ => Err(RuntimeError::InvalidOperation(
1370 format!("key_of() not supported for {:?}", obj).into(),
1371 )),
1372 })
1373 }
1374
1375 pub fn value_of(&self) -> Result<OnionStaticObject, RuntimeError> {
1376 self.with_data(|obj| match obj {
1377 OnionObject::Named(named) => Ok(named.get_value().stabilize()),
1378 OnionObject::Pair(pair) => Ok(pair.get_value().stabilize()),
1379 OnionObject::Undefined(s) => Ok(OnionStaticObject::new(OnionObject::String(Arc::new(
1380 s.as_ref()
1381 .map(|o| o.as_ref().clone())
1382 .unwrap_or_else(|| "".to_string()),
1383 )))),
1384 OnionObject::Custom(custom) => custom.value_of(),
1385 _ => Err(RuntimeError::InvalidOperation(
1386 format!("value_of() not supported for {:?}", obj).into(),
1387 )),
1388 })
1389 }
1390
1391 pub fn type_of(&self) -> Result<String, RuntimeError> {
1392 self.with_data(|obj| match obj {
1393 OnionObject::Integer(_) => Ok("Integer".to_string()),
1394 OnionObject::Float(_) => Ok("Float".to_string()),
1395 OnionObject::String(_) => Ok("String".to_string()),
1396 OnionObject::Bytes(_) => Ok("Bytes".to_string()),
1397 OnionObject::Boolean(_) => Ok("Boolean".to_string()),
1398 OnionObject::Null => Ok("Null".to_string()),
1399 OnionObject::Undefined(_) => Ok("Undefined".to_string()),
1400 OnionObject::Tuple(_) => Ok("Tuple".to_string()),
1401 OnionObject::Pair(_) => Ok("Pair".to_string()),
1402 OnionObject::Named(_) => Ok("Named".to_string()),
1403 OnionObject::LazySet(_) => Ok("LazySet".to_string()),
1404 OnionObject::InstructionPackage(_) => Ok("InstructionPackage".to_string()),
1405 OnionObject::Lambda(_) => Ok("Lambda".to_string()),
1406 OnionObject::Custom(custom) => custom.type_of(),
1407 _ => Err(RuntimeError::InvalidOperation(
1408 format!("type_of() not supported for {:?}", obj).into(),
1409 )),
1410 })
1411 }
1412
1413 #[inline(always)]
1414 pub fn copy(&self) -> Result<OnionStaticObject, RuntimeError> {
1415 self.with_data(|obj| Ok(obj.stabilize()))
1416 }
1417}
1418
1419#[derive(Clone)]
1420pub enum GCArcStorage {
1421 None,
1422 Single(GCArc<OnionObjectCell>),
1423 Multiple(Arc<Vec<GCArc<OnionObjectCell>>>),
1424}
1425
1426#[derive(Clone)]
1438pub struct OnionStaticObject {
1439 _arcs: GCArcStorage,
1440 obj: OnionObject,
1441}
1442
1443impl Default for OnionStaticObject {
1444 fn default() -> Self {
1445 OnionStaticObject {
1446 obj: OnionObject::Undefined(None),
1447 _arcs: GCArcStorage::None,
1448 }
1449 }
1450}
1451
1452impl Debug for OnionStaticObject {
1453 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1454 write!(f, "OnionStaticObject({:?})", self.obj)
1455 }
1456}
1457
1458impl Display for OnionStaticObject {
1459 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1460 write!(f, "OnionStaticObject({:?})", self.obj)
1461 }
1462}
1463
1464impl OnionStaticObject {
1465 #[inline(always)]
1466 pub fn new(obj: OnionObject) -> Self {
1467 let arcs = match &obj {
1468 OnionObject::Mut(obj) => match obj.upgrade() {
1469 None => GCArcStorage::None,
1470 Some(arc) => GCArcStorage::Single(arc),
1471 },
1472 OnionObject::Boolean(_)
1473 | OnionObject::Integer(_)
1474 | OnionObject::Float(_)
1475 | OnionObject::String(_)
1476 | OnionObject::Bytes(_)
1477 | OnionObject::Null
1478 | OnionObject::Undefined(_)
1479 | OnionObject::Range(_, _)
1480 | OnionObject::InstructionPackage(_) => GCArcStorage::None,
1481 _ => {
1482 let mut arcs = vec![];
1483 obj.upgrade(&mut arcs);
1484 GCArcStorage::Multiple(Arc::new(arcs))
1485 }
1486 };
1487 OnionStaticObject {
1488 obj: obj,
1489 _arcs: arcs,
1490 }
1491 }
1492
1493 #[inline(always)]
1494 pub fn weak(&self) -> &OnionObject {
1495 &self.obj
1496 }
1497
1498 #[inline(always)]
1499 pub fn mutablize(
1500 &self,
1501 gc: &mut GC<OnionObjectCell>,
1502 ) -> Result<OnionStaticObject, RuntimeError> {
1503 self.obj.with_data(|obj| Ok(obj.clone().mutablize(gc)))
1504 }
1505}
1506
1507#[macro_export]
1508macro_rules! unwrap_object {
1509 ($obj:expr, $variant:path) => {
1510 match $obj {
1511 $variant(o) => Ok(o),
1512 _ => Err(RuntimeError::InvalidType(
1513 format!("Expected {}, found {:?}", stringify!($variant), $obj).into(),
1514 )),
1515 }
1516 };
1517}
1518
1519#[cfg(test)]
1520mod tests {
1521 use super::*;
1522 use std::time::Instant;
1523
1524 #[test]
1525 fn test_detailed_memory_sizes() {
1526 println!("详细内存分析:");
1527 println!(
1528 "OnionObjectCell: {} bytes",
1529 std::mem::size_of::<OnionObjectCell>()
1530 );
1531 println!("OnionObject: {} bytes", std::mem::size_of::<OnionObject>());
1532 println!(
1533 "OnionStaticObject: {} bytes",
1534 std::mem::size_of::<OnionStaticObject>()
1535 );
1536 println!(
1537 "GCArcStorage: {} bytes",
1538 std::mem::size_of::<GCArcStorage>()
1539 );
1540 println!(
1541 "GCArc<OnionObjectCell>: {} bytes",
1542 std::mem::size_of::<GCArc<OnionObjectCell>>()
1543 );
1544 println!("Arc<String>: {} bytes", std::mem::size_of::<Arc<String>>());
1545 println!(
1546 "Arc<Vec<u8>>: {} bytes",
1547 std::mem::size_of::<Arc<Vec<u8>>>()
1548 );
1549 println!(
1550 "GCArcWeak<OnionObjectCell>: {} bytes",
1551 std::mem::size_of::<GCArcWeak<OnionObjectCell>>()
1552 );
1553 println!("OnionTuple: {} bytes", std::mem::size_of::<OnionTuple>());
1554 println!("OnionNamed: {} bytes", std::mem::size_of::<OnionNamed>());
1555 println!("OnionPair: {} bytes", std::mem::size_of::<OnionPair>());
1556 println!(
1557 "OnionLazySet: {} bytes",
1558 std::mem::size_of::<OnionLazySet>()
1559 );
1560 }
1561
1562 #[test]
1563 fn benchmark_realistic_vm_operations() {
1564 println!("真实VM操作性能测试 (使用OnionStaticObject + clone):");
1565
1566 let start = Instant::now();
1568 let mut result_sum = 0i64;
1569
1570 for i in 0..5_000_000 {
1571 let obj1 = OnionObject::Integer(i).stabilize();
1573 let obj2 = OnionObject::Integer(i + 1).stabilize();
1574
1575 let result = obj1.weak().with_data(|data1| {
1577 obj2.weak().with_data(|data2| {
1578 match (data1, data2) {
1580 (OnionObject::Integer(a), OnionObject::Integer(b)) => {
1581 Ok(OnionObject::Integer(a + b).stabilize())
1582 }
1583 _ => Err(RuntimeError::InvalidOperation(
1584 "Type error".to_string().into(),
1585 )),
1586 }
1587 })
1588 });
1589
1590 if let Ok(sum) = result {
1591 if let Ok(val) = sum.weak().with_data(|data| match data {
1593 OnionObject::Integer(v) => Ok(*v),
1594 _ => Err(RuntimeError::InvalidType("Not integer".to_string().into())),
1595 }) {
1596 result_sum += val;
1597 }
1598 }
1599 }
1600
1601 let duration = start.elapsed();
1602 println!("500万次VM风格整数运算: {:.2}s", duration.as_secs_f64());
1603 println!("每秒操作数: {:.0}", 5_000_000.0 / duration.as_secs_f64());
1604 println!("结果校验: {}", result_sum);
1605 }
1606
1607 #[test]
1608 fn benchmark_vm_style_arithmetic() {
1609 println!("VM风格算术运算性能测试:");
1610
1611 let start = Instant::now();
1612 let mut final_result = 0i64;
1613
1614 for i in 0..2_000_000 {
1615 let left = OnionObject::Integer(i).stabilize();
1617 let right = OnionObject::Integer(i + 1).stabilize();
1618
1619 if let Ok(result) = left
1621 .weak()
1622 .with_data(|l_data| right.weak().with_data(|r_data| l_data.binary_add(r_data)))
1623 {
1624 let multiplier = OnionObject::Integer(2).stabilize();
1626 if let Ok(mul_result) = result.weak().with_data(|add_data| {
1627 multiplier
1628 .weak()
1629 .with_data(|mul_data| add_data.binary_mul(mul_data))
1630 }) {
1631 if let Ok(val) = mul_result.weak().with_data(|data| data.to_integer()) {
1633 final_result += val;
1634 }
1635 }
1636 }
1637 }
1638
1639 let duration = start.elapsed();
1640 println!("200万次复合运算: {:.2}s", duration.as_secs_f64());
1641 println!("每秒操作数: {:.0}", 2_000_000.0 / duration.as_secs_f64());
1642 println!("最终结果: {}", final_result);
1643 }
1644
1645 #[test]
1646 fn benchmark_object_creation_overhead() {
1647 println!("对象创建开销测试:");
1648
1649 let start = Instant::now();
1651 let mut objects = Vec::with_capacity(1_000_000);
1652
1653 for i in 0..1_000_000 {
1654 let obj = OnionObject::Integer(i).stabilize();
1655 objects.push(obj);
1656 }
1657
1658 let creation_time = start.elapsed();
1659 println!(
1660 "100万个OnionStaticObject创建: {:.2}s",
1661 creation_time.as_secs_f64()
1662 );
1663
1664 let start = Instant::now();
1666 let mut sum = 0i64;
1667
1668 for obj in &objects {
1669 if let Ok(val) = obj.weak().with_data(|data| data.to_integer()) {
1670 sum += val;
1671 }
1672 }
1673
1674 let access_time = start.elapsed();
1675 println!("100万次对象访问: {:.2}s", access_time.as_secs_f64());
1676 println!("访问校验和: {}", sum);
1677
1678 let start = Instant::now();
1680 let mut cloned_objects = Vec::with_capacity(objects.len());
1681
1682 for obj in &objects[..100_000] {
1683 cloned_objects.push(obj.clone());
1685 }
1686
1687 let clone_time = start.elapsed();
1688 println!("10万个对象克隆: {:.2}s", clone_time.as_secs_f64());
1689 }
1690
1691 #[test]
1692 fn benchmark_string_operations_realistic() {
1693 println!("真实字符串操作性能测试:");
1694
1695 let start = Instant::now();
1696 let mut total_length = 0usize;
1697
1698 for i in 0..500_000 {
1699 let str_obj = OnionObject::String(Arc::new(format!("string_{}", i))).stabilize();
1701
1702 if let Ok(len_obj) = str_obj.weak().with_data(|data| data.len()) {
1704 if let Ok(length) = len_obj.weak().with_data(|data| data.to_integer()) {
1705 total_length += length as usize;
1706 }
1707 }
1708
1709 let suffix = OnionObject::String(Arc::new("_suffix".to_string())).stabilize();
1711 if let Ok(concat_result) = str_obj.weak().with_data(|str_data| {
1712 suffix
1713 .weak()
1714 .with_data(|suffix_data| str_data.binary_add(suffix_data))
1715 }) {
1716 if let Ok(concat_str) = concat_result
1718 .weak()
1719 .with_data(|data| data.to_string(&mut vec![]))
1720 {
1721 total_length += concat_str.len();
1722 }
1723 }
1724 }
1725
1726 let duration = start.elapsed();
1727 println!("50万次字符串操作: {:.2}s", duration.as_secs_f64());
1728 println!("每秒操作数: {:.0}", 500_000.0 / duration.as_secs_f64());
1729 println!("总字符串长度: {}", total_length);
1730 }
1731
1732 #[test]
1733 fn benchmark_refcell_overhead() {
1734 println!("RefCell开销分析:");
1735
1736 let direct_integers: Vec<i64> = (0..1_000_000).collect();
1738 let wrapped_integers: Vec<OnionStaticObject> = (0..1_000_000)
1739 .map(|i| OnionObject::Integer(i).stabilize())
1740 .collect();
1741
1742 let start = Instant::now();
1744 let mut sum1 = 0i64;
1745 for &val in &direct_integers {
1746 sum1 += val * 2;
1747 }
1748 let direct_time = start.elapsed();
1749
1750 let start = Instant::now();
1752 let mut sum2 = 0i64;
1753 for obj in &wrapped_integers {
1754 if let Ok(val) = obj.weak().with_data(|data| match data {
1755 OnionObject::Integer(i) => Ok(*i),
1756 _ => Err(RuntimeError::InvalidType("Not integer".to_string().into())),
1757 }) {
1758 sum2 += val * 2;
1759 }
1760 }
1761 let refcell_time = start.elapsed();
1762
1763 println!("直接访问100万个i64: {:.2}s", direct_time.as_secs_f64());
1764 println!(
1765 "RefCell访问100万个OnionObject: {:.2}s",
1766 refcell_time.as_secs_f64()
1767 );
1768 println!(
1769 "RefCell开销倍数: {:.1}x",
1770 refcell_time.as_secs_f64() / direct_time.as_secs_f64()
1771 );
1772 println!("校验: {} vs {}", sum1, sum2);
1773 }
1774}