1use std::mem::ManuallyDrop;
2use std::rc::Rc;
3
4use num_bigint::BigInt;
5use num_traits::{One, ToPrimitive, Zero};
6use tycho_types::error::Error;
7use tycho_types::prelude::*;
8
9use crate::cont::{Cont, RcCont, load_cont};
10use crate::error::{VmError, VmResult};
11use crate::saferc::{SafeDelete, SafeRc, SafeRcMakeMut};
12use crate::util::{OwnedCellSlice, ensure_empty_slice};
13
14#[derive(Debug, Default, Clone)]
16pub struct Stack {
17 pub items: Vec<RcStackValue>,
18}
19
20impl Stack {
21 pub const MAX_DEPTH: usize = 0xffffff;
22
23 pub fn make_null() -> RcStackValue {
24 thread_local! {
25 static NULL: RcStackValue = SafeRc::new_dyn_value(());
26 }
27 NULL.with(SafeRc::clone)
28 }
29
30 pub fn make_nan() -> RcStackValue {
31 thread_local! {
32 static NAN: RcStackValue = SafeRc::new_dyn_value(NaN);
33 }
34 NAN.with(SafeRc::clone)
35 }
36
37 pub fn make_empty_tuple() -> RcStackValue {
38 thread_local! {
39 static EMPTY_TUPLE: RcStackValue = SafeRc::new_dyn_value(Vec::new());
40 }
41 EMPTY_TUPLE.with(SafeRc::clone)
42 }
43
44 pub fn make_zero() -> RcStackValue {
45 thread_local! {
46 static ONE: RcStackValue = SafeRc::new_dyn_value(BigInt::zero());
47 }
48 ONE.with(SafeRc::clone)
49 }
50
51 pub fn make_minus_one() -> RcStackValue {
52 thread_local! {
53 static MINUS_ONE: RcStackValue = SafeRc::new_dyn_value(-BigInt::one());
54 }
55 MINUS_ONE.with(SafeRc::clone)
56 }
57
58 pub fn make_one() -> RcStackValue {
59 thread_local! {
60 static ONE: RcStackValue = SafeRc::new_dyn_value(BigInt::one());
61 }
62 ONE.with(SafeRc::clone)
63 }
64
65 pub fn make_bool(value: bool) -> RcStackValue {
66 if value {
67 Self::make_minus_one()
68 } else {
69 Self::make_zero()
70 }
71 }
72
73 pub fn load_stack_value_from_cell(cell: &DynCell) -> Result<RcStackValue, Error> {
75 let slice = &mut ok!(cell.as_slice());
76 let res = ok!(Self::load_stack_value(slice));
77 ok!(ensure_empty_slice(slice));
78 Ok(res)
79 }
80
81 pub fn load_stack_value(slice: &mut CellSlice) -> Result<RcStackValue, Error> {
83 let ty = ok!(slice.load_u8());
84 Ok(match ty {
85 0 => Stack::make_null(),
87 1 => {
89 let value = ok!(slice.load_u64()) as i64;
90 SafeRc::new_dyn_value(BigInt::from(value))
91 }
92 2 => {
93 let t = ok!(slice.get_u8(0));
94 if t == 0xff {
95 ok!(slice.skip_first(8, 0));
97 Stack::make_nan()
98 } else if t / 2 == 0 {
99 ok!(slice.skip_first(7, 0));
101 SafeRc::new_dyn_value(ok!(slice.load_bigint(257, true)))
102 } else {
103 return Err(Error::InvalidData);
104 }
105 }
106 3 => SafeRc::new_dyn_value(ok!(slice.load_reference_cloned())),
108 4 => SafeRc::new_dyn_value(ok!(load_slice_as_stack_value(slice))),
110 5 => {
112 let cell = ok!(slice.load_reference());
113 let mut builder = CellBuilder::new();
114 ok!(builder.store_slice(cell.as_slice_allow_exotic()));
115 SafeRc::new_dyn_value(builder)
116 }
117 6 => ok!(load_cont(slice)).into_dyn_value(),
119 7 => {
121 let len = ok!(slice.load_u16()) as usize;
122 let mut tuple = Vec::with_capacity(std::cmp::min(len, 128));
123
124 match len {
125 0 => {}
126 1 => {
127 let value = ok!(slice.load_reference());
128 tuple.push(ok!(Self::load_stack_value_from_cell(value)));
129 }
130 _ => {
131 let mut head = ok!(slice.load_reference());
132 let mut tail = ok!(slice.load_reference());
133 tuple.push(ok!(Self::load_stack_value_from_cell(tail)));
134
135 for _ in 0..len - 2 {
136 let slice = &mut ok!(head.as_slice());
137 head = ok!(slice.load_reference());
138 tail = ok!(slice.load_reference());
139 ok!(ensure_empty_slice(slice));
140 tuple.push(ok!(Self::load_stack_value_from_cell(tail)));
141 }
142
143 tuple.push(ok!(Self::load_stack_value_from_cell(head)));
144 tuple.reverse();
145 }
146 }
147
148 SafeRc::new_dyn_value(tuple)
149 }
150 _ => return Err(Error::InvalidTag),
151 })
152 }
153
154 pub fn with_items(items: Vec<RcStackValue>) -> Self {
155 Self { items }
156 }
157
158 pub fn depth(&self) -> usize {
159 self.items.len()
160 }
161
162 pub fn display_dump(&self, verbose: bool) -> impl std::fmt::Display + '_ {
163 struct DisplayStack<'a> {
164 items: &'a Vec<RcStackValue>,
165 #[allow(unused)]
166 verbose: bool,
167 }
168
169 impl std::fmt::Display for DisplayStack<'_> {
170 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
171 (self.items as &dyn StackValue).display_list().fmt(f)
172 }
173 }
174
175 DisplayStack {
176 items: &self.items,
177 verbose,
178 }
179 }
180
181 pub fn reserve(&mut self, additional: usize) {
183 self.items.reserve(additional);
184 }
185
186 pub fn push<T: StackValue + 'static>(&mut self, item: T) -> VmResult<()> {
187 self.push_raw(SafeRc::new_dyn_value(item))
188 }
189
190 pub fn push_raw<T: StackValue + ?Sized + 'static>(&mut self, item: SafeRc<T>) -> VmResult<()> {
191 vm_ensure!(
192 self.depth() < Self::MAX_DEPTH,
193 StackUnderflow(Self::MAX_DEPTH)
194 );
195
196 self.items.push(item.into_dyn_value());
197 Ok(())
198 }
199
200 pub fn push_opt<T: StackValue + 'static>(&mut self, value: Option<T>) -> VmResult<()> {
201 match value {
202 None => self.push_null(),
203 Some(value) => self.push(value),
204 }
205 }
206
207 pub fn push_opt_raw<T: StackValue + ?Sized + 'static>(
208 &mut self,
209 item: Option<SafeRc<T>>,
210 ) -> VmResult<()> {
211 match item {
212 None => self.push_null(),
213 Some(item) => self.push_raw(item),
214 }
215 }
216
217 pub fn push_nth(&mut self, idx: usize) -> VmResult<()> {
218 let depth = self.depth();
219 vm_ensure!(idx < depth, StackUnderflow(idx));
220 vm_ensure!(depth + 1 < Self::MAX_DEPTH, StackUnderflow(Self::MAX_DEPTH));
221 self.items.push(self.items[depth - idx - 1].clone());
222 Ok(())
223 }
224
225 pub fn push_null(&mut self) -> VmResult<()> {
226 self.push_raw(Self::make_null())
227 }
228
229 pub fn push_nan(&mut self) -> VmResult<()> {
230 self.push_raw(Self::make_nan())
231 }
232
233 pub fn push_bool(&mut self, value: bool) -> VmResult<()> {
234 self.push_raw(Self::make_bool(value))
235 }
236
237 pub fn push_zero(&mut self) -> VmResult<()> {
238 self.push_raw(Self::make_zero())
239 }
240
241 pub fn push_int<T: Into<BigInt>>(&mut self, value: T) -> VmResult<()> {
242 self.push(value.into())
244 }
245
246 pub fn push_raw_int(&mut self, value: SafeRc<BigInt>, quiet: bool) -> VmResult<()> {
247 if value.bitsize(true) <= 257 {
248 self.push_raw(value)
249 } else if quiet {
250 self.push_nan()
251 } else {
252 vm_bail!(IntegerOverflow)
253 }
254 }
255
256 pub fn move_from_stack(&mut self, other: &mut Self, n: usize) -> VmResult<()> {
257 let Some(new_other_len) = other.depth().checked_sub(n) else {
258 vm_bail!(StackUnderflow(n));
259 };
260 self.items.extend(other.items.drain(new_other_len..));
261 Ok(())
262 }
263
264 pub fn split_top(&mut self, n: usize) -> VmResult<SafeRc<Self>> {
265 let Some(new_depth) = self.depth().checked_sub(n) else {
266 vm_bail!(StackUnderflow(n));
267 };
268 Ok(SafeRc::new(Self {
269 items: self.items.drain(new_depth..).collect(),
270 }))
271 }
272
273 pub fn split_top_ext(&mut self, n: usize, drop: usize) -> VmResult<SafeRc<Self>> {
274 let Some(new_depth) = self.depth().checked_sub(n + drop) else {
275 vm_bail!(StackUnderflow(n + drop));
276 };
277 let res = SafeRc::new(Self {
278 items: self.items.drain(new_depth + drop..).collect(),
279 });
280 self.items.truncate(new_depth);
281 Ok(res)
282 }
283
284 pub fn pop(&mut self) -> VmResult<RcStackValue> {
285 let Some(item) = self.items.pop() else {
286 vm_bail!(StackUnderflow(0));
287 };
288 Ok(item)
289 }
290
291 pub fn pop_bool(&mut self) -> VmResult<bool> {
292 Ok(!ok!(self.pop_int()).is_zero())
293 }
294
295 pub fn pop_int(&mut self) -> VmResult<SafeRc<BigInt>> {
296 ok!(self.pop()).into_int()
297 }
298
299 pub fn pop_int_or_nan(&mut self) -> VmResult<Option<SafeRc<BigInt>>> {
300 let value = ok!(self.pop());
301 if value.raw_ty() == StackValueType::Int as u8 && value.as_int().is_none() {
302 Ok(None)
303 } else {
304 value.into_int().map(Some)
305 }
306 }
307
308 pub fn pop_smallint_range(&mut self, min: u32, max: u32) -> VmResult<u32> {
309 let item = self.pop_int()?;
310 if let Some(item) = item.to_u32() {
311 if item >= min && item <= max {
312 return Ok(item);
313 }
314 }
315 vm_bail!(IntegerOutOfRange {
316 min: min as isize,
317 max: max as isize,
318 actual: item.to_string(),
319 })
320 }
321
322 pub fn pop_long_range(&mut self, min: u64, max: u64) -> VmResult<u64> {
323 let item = self.pop_int()?;
324 if let Some(item) = item.to_u64() {
325 if item >= min && item <= max {
326 return Ok(item);
327 }
328 }
329 vm_bail!(IntegerOutOfRange {
330 min: min as isize,
331 max: max as isize,
332 actual: item.to_string(),
333 })
334 }
335
336 pub fn pop_smallint_signed_range(&mut self, min: i32, max: i32) -> VmResult<i32> {
337 let item = self.pop_int()?;
338 into_signed_range(item, min, max)
339 }
340
341 pub fn pop_smallint_signed_range_or_null(
342 &mut self,
343 min: i32,
344 max: i32,
345 ) -> VmResult<Option<i32>> {
346 let item = ok!(self.pop());
347 if item.raw_ty() == StackValueType::Null as u8 {
348 return Ok(None);
349 }
350 into_signed_range(item.into_int()?, min, max).map(Some)
351 }
352
353 pub fn pop_tuple(&mut self) -> VmResult<SafeRc<Tuple>> {
354 self.pop()?.into_tuple()
355 }
356
357 pub fn pop_tuple_range(&mut self, min_len: u32, max_len: u32) -> VmResult<SafeRc<Tuple>> {
358 let tuple = self.pop()?.into_tuple()?;
359 vm_ensure!(
360 (min_len as usize..=max_len as usize).contains(&tuple.len()),
361 InvalidType {
362 expected: StackValueType::Tuple as _,
363 actual: StackValueType::Tuple as _,
364 }
365 );
366 Ok(tuple)
367 }
368
369 pub fn pop_opt_tuple_range(
370 &mut self,
371 min_len: u32,
372 max_len: u32,
373 ) -> VmResult<Option<SafeRc<Tuple>>> {
374 let tuple = {
375 let value = self.pop()?;
376 if value.is_null() {
377 return Ok(None);
378 }
379 value.into_tuple()?
380 };
381
382 vm_ensure!(
383 (min_len as usize..=max_len as usize).contains(&tuple.len()),
384 InvalidType {
385 expected: StackValueType::Tuple as _,
386 actual: StackValueType::Tuple as _,
387 }
388 );
389 Ok(Some(tuple))
390 }
391
392 pub fn pop_cont(&mut self) -> VmResult<RcCont> {
393 self.pop()?.into_cont()
394 }
395
396 pub fn pop_cs(&mut self) -> VmResult<SafeRc<OwnedCellSlice>> {
397 self.pop()?.into_cell_slice()
398 }
399
400 pub fn pop_builder(&mut self) -> VmResult<SafeRc<CellBuilder>> {
401 self.pop()?.into_cell_builder()
402 }
403
404 pub fn pop_cell(&mut self) -> VmResult<SafeRc<Cell>> {
405 self.pop()?.into_cell()
406 }
407
408 pub fn pop_cell_opt(&mut self) -> VmResult<Option<SafeRc<Cell>>> {
409 let sv = self.pop()?;
410 if sv.is_null() {
411 Ok(None)
412 } else {
413 sv.into_cell().map(Some)
414 }
415 }
416
417 pub fn pop_many(&mut self, n: usize) -> VmResult<()> {
418 let Some(new_len) = self.depth().checked_sub(n) else {
419 vm_bail!(StackUnderflow(n));
420 };
421 self.items.truncate(new_len);
422 Ok(())
423 }
424
425 pub fn drop_bottom(&mut self, n: usize) -> VmResult<()> {
426 vm_ensure!(n <= self.depth(), StackUnderflow(n));
427 self.items.drain(..n);
428 Ok(())
429 }
430
431 pub fn swap(&mut self, lhs: usize, rhs: usize) -> VmResult<()> {
432 let depth = self.depth();
433 vm_ensure!(lhs < depth, StackUnderflow(lhs));
434 vm_ensure!(rhs < depth, StackUnderflow(rhs));
435 self.items.swap(depth - lhs - 1, depth - rhs - 1);
436 Ok(())
437 }
438
439 pub fn reverse_range(&mut self, offset: usize, n: usize) -> VmResult<()> {
440 let depth = self.depth();
441 vm_ensure!(offset < depth, StackUnderflow(offset));
442 vm_ensure!(offset + n <= depth, StackUnderflow(offset + n));
443 self.items[depth - offset - n..depth - offset].reverse();
444 Ok(())
445 }
446
447 pub fn fetch(&self, idx: usize) -> VmResult<&RcStackValue> {
448 let depth = self.depth();
449 vm_ensure!(idx < depth, StackUnderflow(idx));
450 Ok(&self.items[depth - idx - 1])
451 }
452
453 pub fn get_exit_arg(&self) -> Option<i32> {
454 let last = self.items.last()?;
455 let last = last.as_int()?;
456 last.to_i32()
457 }
458}
459
460fn into_signed_range(item: SafeRc<BigInt>, min: i32, max: i32) -> VmResult<i32> {
461 if let Some(item) = item.to_i32() {
462 if item >= min && item <= max {
463 return Ok(item);
464 }
465 }
466 vm_bail!(IntegerOutOfRange {
467 min: min as isize,
468 max: max as isize,
469 actual: item.to_string(),
470 })
471}
472
473impl SafeRcMakeMut for Stack {
474 #[inline]
475 fn rc_make_mut(rc: &mut Rc<Self>) -> &mut Self {
476 Rc::make_mut(rc)
477 }
478}
479
480impl FromIterator<RcStackValue> for Stack {
481 #[inline]
482 fn from_iter<T: IntoIterator<Item = RcStackValue>>(iter: T) -> Self {
483 Self {
484 items: Vec::<RcStackValue>::from_iter(iter),
485 }
486 }
487}
488
489impl Store for Stack {
491 fn store_into(
492 &self,
493 builder: &mut CellBuilder,
494 context: &dyn CellContext,
495 ) -> Result<(), Error> {
496 let depth = self.depth();
497 if depth > Self::MAX_DEPTH {
498 return Err(Error::IntOverflow);
499 }
500 ok!(builder.store_uint(depth as _, 24));
501
502 if let Some((last, items)) = self.items.split_last() {
503 let mut rest = Cell::empty_cell();
504 for item in items {
505 let mut builder = CellBuilder::new();
506 ok!(builder.store_reference(rest));
507 ok!(item.store_as_stack_value(&mut builder, context));
508 rest = ok!(builder.build_ext(context));
509 }
510
511 ok!(builder.store_reference(rest));
512 ok!(last.store_as_stack_value(builder, context));
513 }
514 Ok(())
515 }
516}
517
518impl<'a> Load<'a> for Stack {
519 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
520 let depth = ok!(slice.load_uint(24)) as usize;
521 if depth == 0 {
522 return Ok(Stack::default());
523 }
524
525 let mut result = Stack {
526 items: Vec::with_capacity(std::cmp::min(depth, 128)),
527 };
528
529 let mut rest = ok!(slice.load_reference());
530 result.items.push(ok!(Self::load_stack_value(slice)));
531
532 if depth > 1 {
533 for _ in 0..depth - 1 {
534 let slice = &mut ok!(rest.as_slice());
535 rest = ok!(slice.load_reference());
536 result.items.push(ok!(Self::load_stack_value(slice)));
537 ok!(ensure_empty_slice(slice));
538 }
539
540 ok!(ensure_empty_slice(&ok!(rest.as_slice())));
541
542 result.items.reverse();
543 }
544
545 Ok(result)
546 }
547}
548
549pub type RcStackValue = SafeRc<dyn StackValue>;
553
554macro_rules! define_stack_value_type {
555 (
556 $(#[$($meta:tt)*])*
557 $vis:vis enum $ident:ident {
558 $($name:ident = $n:literal),*$(,)?
559 }
560 ) => {
561 $(#[$($meta)*])*
562 $vis enum $ident {
563 $($name = $n,)*
564 }
565
566 impl $ident {
567 pub fn from_raw(value: u8) -> Option<Self> {
568 Some(match value {
569 $($n => Self::$name,)*
570 _ => return None,
571 })
572 }
573 }
574 };
575}
576
577define_stack_value_type! {
578 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
580 #[repr(u8)]
581 #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
582 pub enum StackValueType {
583 Null = 0,
584 Int = 1,
585 Cell = 2,
586 Slice = 3,
587 Builder = 4,
588 Cont = 5,
589 Tuple = 6,
590 }
591}
592
593impl StackValueType {
594 pub fn display_raw(value: u8) -> impl std::fmt::Display + Copy {
595 #[derive(Clone, Copy)]
596 #[repr(transparent)]
597 struct DisplayRaw(u8);
598
599 impl std::fmt::Display for DisplayRaw {
600 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
601 match StackValueType::from_raw(self.0) {
602 Some(ty) => std::fmt::Debug::fmt(&ty, f),
603 None => write!(f, "Type#{}", self.0),
604 }
605 }
606 }
607
608 DisplayRaw(value)
609 }
610}
611
612impl From<StackValueType> for u8 {
613 #[inline]
614 fn from(value: StackValueType) -> Self {
615 value as u8
616 }
617}
618
619pub trait StackValue: SafeDelete + std::fmt::Debug {
621 fn rc_into_dyn(self: Rc<Self>) -> Rc<dyn StackValue>;
622
623 fn raw_ty(&self) -> u8;
624
625 fn store_as_stack_value(
626 &self,
627 builder: &mut CellBuilder,
628 context: &dyn CellContext,
629 ) -> Result<(), Error>;
630
631 fn fmt_dump(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
632
633 fn as_int(&self) -> Option<&BigInt> {
634 None
635 }
636
637 fn try_as_int(&self) -> VmResult<&BigInt> {
638 match self.as_int() {
639 Some(value) => Ok(value),
640 None => Err(invalid_type(self.raw_ty(), StackValueType::Int)),
641 }
642 }
643
644 fn rc_into_int(self: Rc<Self>) -> VmResult<Rc<BigInt>> {
645 Err(invalid_type(self.raw_ty(), StackValueType::Int))
646 }
647
648 fn as_cell(&self) -> Option<&Cell> {
649 None
650 }
651
652 fn try_as_cell(&self) -> VmResult<&Cell> {
653 match self.as_cell() {
654 Some(value) => Ok(value),
655 None => Err(invalid_type(self.raw_ty(), StackValueType::Cell)),
656 }
657 }
658
659 fn rc_into_cell(self: Rc<Self>) -> VmResult<Rc<Cell>> {
660 Err(invalid_type(self.raw_ty(), StackValueType::Cell))
661 }
662
663 fn as_cell_slice(&self) -> Option<&OwnedCellSlice> {
664 None
665 }
666
667 fn try_as_cell_slice(&self) -> VmResult<&OwnedCellSlice> {
668 match self.as_cell_slice() {
669 Some(value) => Ok(value),
670 None => Err(invalid_type(self.raw_ty(), StackValueType::Slice)),
671 }
672 }
673
674 fn rc_into_cell_slice(self: Rc<Self>) -> VmResult<Rc<OwnedCellSlice>> {
675 Err(invalid_type(self.raw_ty(), StackValueType::Slice))
676 }
677
678 fn as_cell_builder(&self) -> Option<&CellBuilder> {
679 None
680 }
681
682 fn try_as_cell_builder(&self) -> VmResult<&CellBuilder> {
683 match self.as_cell_builder() {
684 Some(value) => Ok(value),
685 None => Err(invalid_type(self.raw_ty(), StackValueType::Builder)),
686 }
687 }
688
689 fn rc_into_cell_builder(self: Rc<Self>) -> VmResult<Rc<CellBuilder>> {
690 Err(invalid_type(self.raw_ty(), StackValueType::Builder))
691 }
692
693 fn as_cont(&self) -> Option<&dyn Cont> {
694 None
695 }
696
697 fn try_as_cont(&self) -> VmResult<&dyn Cont> {
698 match self.as_cont() {
699 Some(value) => Ok(value),
700 None => Err(invalid_type(self.raw_ty(), StackValueType::Cont)),
701 }
702 }
703
704 fn rc_into_cont(self: Rc<Self>) -> VmResult<Rc<dyn Cont>> {
705 Err(invalid_type(self.raw_ty(), StackValueType::Cont))
706 }
707
708 fn as_tuple(&self) -> Option<&[RcStackValue]> {
709 None
710 }
711
712 fn try_as_tuple(&self) -> VmResult<&[RcStackValue]> {
713 match self.as_tuple() {
714 Some(value) => Ok(value),
715 None => Err(invalid_type(self.raw_ty(), StackValueType::Tuple)),
716 }
717 }
718
719 fn rc_into_tuple(self: Rc<Self>) -> VmResult<Rc<Tuple>> {
720 Err(invalid_type(self.raw_ty(), StackValueType::Tuple))
721 }
722}
723
724impl dyn StackValue + '_ {
725 pub fn is_null(&self) -> bool {
726 self.raw_ty() == StackValueType::Null as u8
727 }
728
729 pub fn is_tuple(&self) -> bool {
730 self.raw_ty() == StackValueType::Tuple as u8
731 }
732
733 pub fn as_tuple_range(&self, min_len: u32, max_len: u32) -> Option<&[RcStackValue]> {
734 let tuple = self.as_tuple()?;
735 (min_len as usize..=max_len as usize)
736 .contains(&tuple.len())
737 .then_some(tuple)
738 }
739
740 pub fn as_pair(&self) -> Option<(&dyn StackValue, &dyn StackValue)> {
741 match self.as_tuple()? {
742 [first, second] => Some((first.as_ref(), second.as_ref())),
743 _ => None,
744 }
745 }
746
747 pub fn as_list(&self) -> Option<(&dyn StackValue, &dyn StackValue)> {
748 let (head, tail) = self.as_pair()?;
749
750 let mut next = tail;
751 while !next.is_null() {
752 let (_, tail) = next.as_pair()?;
753 next = tail;
754 }
755
756 Some((head, tail))
757 }
758
759 pub fn display_list(&self) -> impl std::fmt::Display + '_ {
760 pub struct DisplayList<'a>(&'a dyn StackValue);
761
762 impl std::fmt::Display for DisplayList<'_> {
763 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
764 self.0.fmt_list(f)
765 }
766 }
767
768 DisplayList(self)
769 }
770
771 fn fmt_list(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
772 if self.is_null() {
773 f.write_str("()")
774 } else if let Some(tuple) = self.as_tuple() {
775 if let Some((head, tail)) = self.as_list() {
776 f.write_str("(")?;
777 head.fmt_list(f)?;
778 tail.fmt_list_tail(f)?;
779 return Ok(());
780 }
781
782 f.write_str("[")?;
783 let mut first = true;
784 for item in tuple {
785 if !std::mem::take(&mut first) {
786 f.write_str(" ")?;
787 }
788 item.as_ref().fmt_list(f)?;
789 }
790 f.write_str("]")?;
791
792 Ok(())
793 } else {
794 self.fmt_dump(f)
795 }
796 }
797
798 fn fmt_list_tail(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
799 let mut item = self;
800 while !item.is_null() {
801 let Some((head, tail)) = item.as_pair() else {
802 f.write_str(" . ")?;
803 item.fmt_list(f)?;
804 break;
805 };
806
807 f.write_str(" ")?;
808 head.fmt_list(f)?;
809 item = tail;
810 }
811 f.write_str(")")
812 }
813}
814
815pub trait StaticStackValue: StackValue {
817 type DynRef<'a>;
818
819 fn known_ty() -> StackValueType;
820 fn from_dyn(value: Rc<dyn StackValue>) -> VmResult<Rc<Self>>;
821 fn from_dyn_ref(value: &dyn StackValue) -> VmResult<Self::DynRef<'_>>;
822}
823
824fn invalid_type(actual: u8, expected: StackValueType) -> Box<VmError> {
825 Box::new(VmError::InvalidType {
826 expected: expected as _,
827 actual,
828 })
829}
830
831impl StackValue for () {
834 #[inline]
835 fn rc_into_dyn(self: Rc<Self>) -> Rc<dyn StackValue> {
836 self
837 }
838
839 fn raw_ty(&self) -> u8 {
840 StackValueType::Null as _
841 }
842
843 fn store_as_stack_value(
844 &self,
845 builder: &mut CellBuilder,
846 _: &dyn CellContext,
847 ) -> Result<(), Error> {
848 builder.store_zeros(8)
850 }
851
852 fn fmt_dump(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
853 f.write_str("(null)")
854 }
855}
856
857#[derive(Debug, Clone, Copy)]
861pub struct NaN;
862
863impl StackValue for NaN {
864 #[inline]
865 fn rc_into_dyn(self: Rc<Self>) -> Rc<dyn StackValue> {
866 self
867 }
868
869 fn raw_ty(&self) -> u8 {
870 StackValueType::Int as _
871 }
872
873 fn store_as_stack_value(
874 &self,
875 builder: &mut CellBuilder,
876 _: &dyn CellContext,
877 ) -> Result<(), Error> {
878 builder.store_u16(0x02ff)
880 }
881
882 fn fmt_dump(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
883 f.write_str("NaN")
884 }
885
886 fn try_as_int(&self) -> VmResult<&BigInt> {
887 vm_bail!(IntegerOverflow);
888 }
889
890 fn rc_into_int(self: Rc<Self>) -> VmResult<Rc<BigInt>> {
891 vm_bail!(IntegerOverflow);
892 }
893}
894
895impl SafeRcMakeMut for NaN {
896 #[inline]
897 fn rc_make_mut(rc: &mut Rc<Self>) -> &mut Self {
898 Rc::make_mut(rc)
899 }
900}
901
902impl StackValue for BigInt {
905 #[inline]
906 fn rc_into_dyn(self: Rc<Self>) -> Rc<dyn StackValue> {
907 self
908 }
909
910 fn raw_ty(&self) -> u8 {
911 StackValueType::Int as _
912 }
913
914 fn store_as_stack_value(
915 &self,
916 builder: &mut CellBuilder,
917 _: &dyn CellContext,
918 ) -> Result<(), Error> {
919 let bitsize = self.bitsize(true);
920 if bitsize <= 64 {
921 ok!(builder.store_u8(0x01));
923 builder.store_bigint(self, 64, true)
924 } else {
925 ok!(builder.store_uint(0x0200 >> 1, 15));
927 builder.store_bigint(self, 257, true)
928 }
929 }
930
931 fn fmt_dump(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
932 std::fmt::Display::fmt(self, f)
933 }
934
935 fn as_int(&self) -> Option<&BigInt> {
936 Some(self)
937 }
938
939 fn rc_into_int(self: Rc<Self>) -> VmResult<Rc<BigInt>> {
940 Ok(self)
941 }
942}
943
944impl StaticStackValue for BigInt {
945 type DynRef<'a> = &'a BigInt;
946
947 fn known_ty() -> StackValueType {
948 StackValueType::Int
949 }
950
951 fn from_dyn(value: Rc<dyn StackValue>) -> VmResult<Rc<Self>> {
952 value.rc_into_int()
953 }
954
955 fn from_dyn_ref(value: &dyn StackValue) -> VmResult<Self::DynRef<'_>> {
956 match value.as_int() {
957 Some(value) => Ok(value),
958 None => vm_bail!(InvalidType {
959 expected: StackValueType::Int as _,
960 actual: value.raw_ty(),
961 }),
962 }
963 }
964}
965
966impl SafeRcMakeMut for BigInt {
967 #[inline]
968 fn rc_make_mut(rc: &mut Rc<Self>) -> &mut Self {
969 Rc::make_mut(rc)
970 }
971}
972
973impl StackValue for Cell {
976 #[inline]
977 fn rc_into_dyn(self: Rc<Self>) -> Rc<dyn StackValue> {
978 self
979 }
980
981 fn raw_ty(&self) -> u8 {
982 StackValueType::Cell as _
983 }
984
985 fn store_as_stack_value(
986 &self,
987 builder: &mut CellBuilder,
988 _: &dyn CellContext,
989 ) -> Result<(), Error> {
990 ok!(builder.store_u8(0x03));
992 builder.store_reference(self.clone())
993 }
994
995 fn fmt_dump(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
996 write!(f, "C{{{:X}}}", self.repr_hash())
997 }
998
999 fn as_cell(&self) -> Option<&Cell> {
1000 Some(self)
1001 }
1002
1003 fn rc_into_cell(self: Rc<Self>) -> VmResult<Rc<Cell>> {
1004 Ok(self)
1005 }
1006}
1007
1008impl StaticStackValue for Cell {
1009 type DynRef<'a> = &'a Cell;
1010
1011 fn known_ty() -> StackValueType {
1012 StackValueType::Cell
1013 }
1014
1015 fn from_dyn(value: Rc<dyn StackValue>) -> VmResult<Rc<Self>> {
1016 value.rc_into_cell()
1017 }
1018
1019 fn from_dyn_ref(value: &dyn StackValue) -> VmResult<Self::DynRef<'_>> {
1020 match value.as_cell() {
1021 Some(value) => Ok(value),
1022 None => vm_bail!(InvalidType {
1023 expected: StackValueType::Cell as _,
1024 actual: value.raw_ty(),
1025 }),
1026 }
1027 }
1028}
1029
1030impl SafeRcMakeMut for Cell {
1031 #[inline]
1032 fn rc_make_mut(rc: &mut Rc<Self>) -> &mut Self {
1033 Rc::make_mut(rc)
1034 }
1035}
1036
1037impl StackValue for OwnedCellSlice {
1040 #[inline]
1041 fn rc_into_dyn(self: Rc<Self>) -> Rc<dyn StackValue> {
1042 self
1043 }
1044
1045 fn raw_ty(&self) -> u8 {
1046 StackValueType::Slice as _
1047 }
1048
1049 fn store_as_stack_value(
1050 &self,
1051 builder: &mut CellBuilder,
1052 _: &dyn CellContext,
1053 ) -> Result<(), Error> {
1054 ok!(builder.store_u8(0x04));
1056 store_slice_as_stack_value(self, builder)
1057 }
1058
1059 fn fmt_dump(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1060 std::fmt::Display::fmt(self, f)
1061 }
1062
1063 fn as_cell_slice(&self) -> Option<&OwnedCellSlice> {
1064 Some(self)
1065 }
1066
1067 fn rc_into_cell_slice(self: Rc<Self>) -> VmResult<Rc<OwnedCellSlice>> {
1068 Ok(self)
1069 }
1070}
1071
1072impl StaticStackValue for OwnedCellSlice {
1073 type DynRef<'a> = &'a OwnedCellSlice;
1074
1075 fn known_ty() -> StackValueType {
1076 StackValueType::Slice
1077 }
1078
1079 fn from_dyn(value: Rc<dyn StackValue>) -> VmResult<Rc<Self>> {
1080 value.rc_into_cell_slice()
1081 }
1082
1083 fn from_dyn_ref(value: &dyn StackValue) -> VmResult<Self::DynRef<'_>> {
1084 match value.as_cell_slice() {
1085 Some(value) => Ok(value),
1086 None => vm_bail!(InvalidType {
1087 expected: StackValueType::Slice as _,
1088 actual: value.raw_ty(),
1089 }),
1090 }
1091 }
1092}
1093
1094impl SafeRcMakeMut for OwnedCellSlice {
1095 #[inline]
1096 fn rc_make_mut(rc: &mut Rc<Self>) -> &mut Self {
1097 Rc::make_mut(rc)
1098 }
1099}
1100
1101impl StackValue for CellBuilder {
1104 #[inline]
1105 fn rc_into_dyn(self: Rc<Self>) -> Rc<dyn StackValue> {
1106 self
1107 }
1108
1109 fn raw_ty(&self) -> u8 {
1110 StackValueType::Builder as _
1111 }
1112
1113 fn store_as_stack_value(
1114 &self,
1115 builder: &mut CellBuilder,
1116 context: &dyn CellContext,
1117 ) -> Result<(), Error> {
1118 let mut b = self.clone();
1119 b.set_exotic(false);
1122
1123 ok!(builder.store_u8(0x05));
1125 builder.store_reference(ok!(b.build_ext(context)))
1126 }
1127
1128 fn fmt_dump(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1129 write!(f, "BC{{{}}}", self.display_data())
1130 }
1131
1132 fn as_cell_builder(&self) -> Option<&CellBuilder> {
1133 Some(self)
1134 }
1135
1136 fn rc_into_cell_builder(self: Rc<Self>) -> VmResult<Rc<CellBuilder>> {
1137 Ok(self)
1138 }
1139}
1140
1141impl StaticStackValue for CellBuilder {
1142 type DynRef<'a> = &'a CellBuilder;
1143
1144 fn known_ty() -> StackValueType {
1145 StackValueType::Builder
1146 }
1147
1148 fn from_dyn(value: Rc<dyn StackValue>) -> VmResult<Rc<Self>> {
1149 value.rc_into_cell_builder()
1150 }
1151
1152 fn from_dyn_ref(value: &dyn StackValue) -> VmResult<Self::DynRef<'_>> {
1153 match value.as_cell_builder() {
1154 Some(value) => Ok(value),
1155 None => vm_bail!(InvalidType {
1156 expected: StackValueType::Builder as _,
1157 actual: value.raw_ty(),
1158 }),
1159 }
1160 }
1161}
1162
1163impl SafeRcMakeMut for CellBuilder {
1164 #[inline]
1165 fn rc_make_mut(rc: &mut Rc<Self>) -> &mut Self {
1166 Rc::make_mut(rc)
1167 }
1168}
1169
1170impl StackValue for dyn Cont {
1173 #[inline]
1174 fn rc_into_dyn(self: Rc<Self>) -> Rc<dyn StackValue> {
1175 Cont::rc_into_dyn(self)
1176 }
1177
1178 fn raw_ty(&self) -> u8 {
1179 StackValueType::Cont as _
1180 }
1181
1182 fn store_as_stack_value(
1183 &self,
1184 builder: &mut CellBuilder,
1185 context: &dyn CellContext,
1186 ) -> Result<(), Error> {
1187 ok!(builder.store_u8(0x06));
1189 self.store_into(builder, context)
1190 }
1191
1192 fn fmt_dump(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1193 write!(f, "Cont{{{:?}}}", self as *const _ as *const ())
1194 }
1195
1196 fn as_cont(&self) -> Option<&dyn Cont> {
1197 Some(self)
1198 }
1199
1200 fn rc_into_cont(self: Rc<Self>) -> VmResult<Rc<dyn Cont>> {
1201 Ok(self)
1202 }
1203}
1204
1205impl StaticStackValue for dyn Cont {
1206 type DynRef<'a> = &'a dyn Cont;
1207
1208 fn known_ty() -> StackValueType {
1209 StackValueType::Cont
1210 }
1211
1212 fn from_dyn(value: Rc<dyn StackValue>) -> VmResult<Rc<Self>> {
1213 value.rc_into_cont()
1214 }
1215
1216 fn from_dyn_ref(value: &dyn StackValue) -> VmResult<Self::DynRef<'_>> {
1217 match value.as_cont() {
1218 Some(value) => Ok(value),
1219 None => vm_bail!(InvalidType {
1220 expected: StackValueType::Cont as _,
1221 actual: value.raw_ty(),
1222 }),
1223 }
1224 }
1225}
1226
1227pub type Tuple = Vec<RcStackValue>;
1231
1232pub trait TupleExt {
1234 fn try_get(&self, index: usize) -> VmResult<&RcStackValue>;
1235
1236 fn try_get_owned<V: StaticStackValue>(&self, index: usize) -> VmResult<SafeRc<V>> {
1237 let value = ok!(self.try_get(index));
1238 V::from_dyn(Rc::clone(&*value.0)).map(SafeRc::from)
1239 }
1240
1241 fn try_get_ref<V: StaticStackValue>(&self, index: usize) -> VmResult<V::DynRef<'_>> {
1242 let value = ok!(self.try_get(index));
1243 V::from_dyn_ref(value.as_ref())
1244 }
1245
1246 fn try_get_tuple_range<R>(&self, index: usize, range: R) -> VmResult<&[RcStackValue]>
1247 where
1248 R: std::ops::RangeBounds<usize>,
1249 {
1250 let value = ok!(self.try_get_ref::<Tuple>(index));
1251 if range.contains(&value.len()) {
1252 Ok(value)
1253 } else {
1254 vm_bail!(InvalidType {
1256 expected: StackValueType::Tuple as _,
1257 actual: StackValueType::Null as _
1258 })
1259 }
1260 }
1261}
1262
1263impl TupleExt for [RcStackValue] {
1264 fn try_get(&self, index: usize) -> VmResult<&RcStackValue> {
1265 let Some(value) = self.get(index) else {
1266 vm_bail!(IntegerOutOfRange {
1267 min: 0,
1268 max: self.len() as _,
1269 actual: index.to_string(),
1270 });
1271 };
1272 Ok(value)
1273 }
1274}
1275
1276impl StackValue for Tuple {
1277 #[inline]
1278 fn rc_into_dyn(self: Rc<Self>) -> Rc<dyn StackValue> {
1279 self
1280 }
1281
1282 fn raw_ty(&self) -> u8 {
1283 StackValueType::Tuple as _
1284 }
1285
1286 fn store_as_stack_value(
1287 &self,
1288 builder: &mut CellBuilder,
1289 context: &dyn CellContext,
1290 ) -> Result<(), Error> {
1291 if self.len() > u16::MAX as usize {
1292 return Err(Error::IntOverflow);
1293 }
1294
1295 let mut head = None::<Cell>;
1296 let mut tail = None::<Cell>;
1297
1298 for item in self {
1299 std::mem::swap(&mut head, &mut tail);
1300
1301 if tail.is_some() && head.is_some() {
1302 if let (Some(t), Some(h)) = (tail.take(), head.take()) {
1303 head = Some(ok!(CellBuilder::build_from_ext((t, h), context)));
1304 }
1305 }
1306
1307 let mut builder = CellBuilder::new();
1308 ok!(item.store_as_stack_value(&mut builder, context));
1309 tail = Some(ok!(builder.build_ext(context)));
1310 }
1311
1312 ok!(builder.store_u8(0x07));
1314 ok!(builder.store_u16(self.len() as _));
1315 if let Some(head) = head {
1316 ok!(builder.store_reference(head));
1317 }
1318 if let Some(tail) = tail {
1319 ok!(builder.store_reference(tail));
1320 }
1321 Ok(())
1322 }
1323
1324 fn fmt_dump(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1325 if self.is_empty() {
1326 return f.write_str("[]");
1327 }
1328 f.write_str("[ ")?;
1329 let mut first = true;
1330 for item in self {
1331 if !std::mem::take(&mut first) {
1332 f.write_str(" ")?;
1333 }
1334 StackValue::fmt_dump(item.as_ref(), f)?;
1335 }
1336 f.write_str(" ]")
1337 }
1338
1339 fn as_tuple(&self) -> Option<&[RcStackValue]> {
1340 Some(self)
1341 }
1342
1343 fn rc_into_tuple(self: Rc<Self>) -> VmResult<Rc<Tuple>> {
1344 Ok(self)
1345 }
1346}
1347
1348impl StaticStackValue for Tuple {
1349 type DynRef<'a> = &'a [RcStackValue];
1350
1351 fn known_ty() -> StackValueType {
1352 StackValueType::Tuple
1353 }
1354
1355 fn from_dyn(value: Rc<dyn StackValue>) -> VmResult<Rc<Self>> {
1356 value.rc_into_tuple()
1357 }
1358
1359 fn from_dyn_ref(value: &dyn StackValue) -> VmResult<Self::DynRef<'_>> {
1360 match value.as_tuple() {
1361 Some(value) => Ok(value),
1362 None => vm_bail!(InvalidType {
1363 expected: StackValueType::Tuple as _,
1364 actual: value.raw_ty(),
1365 }),
1366 }
1367 }
1368}
1369
1370pub(crate) fn store_slice_as_stack_value(
1378 slice: &OwnedCellSlice,
1379 builder: &mut CellBuilder,
1380) -> Result<(), Error> {
1381 ok!(builder.store_reference(slice.cell().clone()));
1382
1383 let range = slice.range();
1384 let value = ((range.offset_bits() as u64) << 16)
1385 | (((range.offset_bits() + range.size_bits()) as u64) << 6)
1386 | ((range.offset_refs() as u64) << 3)
1387 | (range.offset_refs() + range.size_refs()) as u64;
1388 builder.store_uint(value, 26)
1389}
1390
1391pub(crate) fn load_slice_as_stack_value(slice: &mut CellSlice) -> Result<OwnedCellSlice, Error> {
1397 let cell = ok!(slice.load_reference_cloned());
1398 let range = ok!(slice.load_uint(26));
1399
1400 let bits_start = (range >> 16) as u16 & 0x3ff;
1401 let bits_end = (range >> 6) as u16 & 0x3ff;
1402 let refs_start = (range >> 3) as u8 & 0b111;
1403 let refs_end = range as u8 & 0b111;
1404
1405 if bits_start > bits_end || refs_start > refs_end || refs_end > 4 {
1406 return Err(Error::InvalidData);
1407 }
1408
1409 if bits_end > cell.bit_len() || refs_end > cell.reference_count() {
1410 return Err(Error::InvalidData);
1411 }
1412
1413 let mut range = CellSliceRange::full(cell.as_ref());
1414 let ok = range.skip_first(bits_start, refs_start).is_ok();
1415 debug_assert!(ok);
1416
1417 let bits = bits_end - bits_start;
1418 let refs = refs_end - refs_start;
1419 let ok = range.only_first(bits, refs).is_ok();
1420 debug_assert!(ok);
1421
1422 Ok(OwnedCellSlice::from((range, cell)))
1423}
1424
1425impl RcStackValue {
1428 #[inline]
1429 pub fn new_dyn_value<T: StackValue + 'static>(value: T) -> Self {
1430 Self(ManuallyDrop::new(Rc::new(value)))
1431 }
1432
1433 #[inline]
1434 pub fn into_int(self) -> VmResult<SafeRc<BigInt>> {
1435 Self::into_inner(self).rc_into_int().map(SafeRc::from)
1436 }
1437
1438 #[inline]
1439 pub fn into_cell(self) -> VmResult<SafeRc<Cell>> {
1440 Self::into_inner(self).rc_into_cell().map(SafeRc::from)
1441 }
1442
1443 #[inline]
1444 pub fn into_cell_slice(self) -> VmResult<SafeRc<OwnedCellSlice>> {
1445 Self::into_inner(self)
1446 .rc_into_cell_slice()
1447 .map(SafeRc::from)
1448 }
1449
1450 #[inline]
1451 pub fn into_cell_builder(self) -> VmResult<SafeRc<CellBuilder>> {
1452 Self::into_inner(self)
1453 .rc_into_cell_builder()
1454 .map(SafeRc::from)
1455 }
1456
1457 #[inline]
1458 pub fn into_cont(self) -> VmResult<SafeRc<dyn Cont>> {
1459 Self::into_inner(self).rc_into_cont().map(SafeRc::from)
1460 }
1461
1462 #[inline]
1463 pub fn into_tuple(self) -> VmResult<SafeRc<Tuple>> {
1464 Self::into_inner(self).rc_into_tuple().map(SafeRc::from)
1465 }
1466}
1467
1468impl<T: StackValue + ?Sized> SafeRc<T> {
1469 #[inline]
1470 pub fn into_dyn_value(self) -> RcStackValue {
1471 let value = SafeRc::into_inner(self);
1472 SafeRc(ManuallyDrop::new(value.rc_into_dyn()))
1473 }
1474}
1475
1476impl<T: StackValue + 'static> From<T> for RcStackValue {
1477 #[inline]
1478 fn from(value: T) -> Self {
1479 Self(ManuallyDrop::new(Rc::new(value)))
1480 }
1481}
1482
1483impl<T: StackValue + 'static> From<Rc<T>> for RcStackValue {
1484 #[inline]
1485 fn from(value: Rc<T>) -> Self {
1486 Self(ManuallyDrop::new(value))
1487 }
1488}
1489
1490#[cfg(test)]
1491mod tests {
1492 use super::*;
1493
1494 #[test]
1495 fn parse_stack_tuple() {
1496 let cell =
1497 Boc::decode_base64("te6cckEBAwEAHQABGAAAAgEAAAAAAAAAAgEBEgEAAAAAAAAAAQIAAHap0w8=")
1498 .unwrap();
1499
1500 let stack = cell.parse::<Stack>().unwrap();
1501 println!("{:#?}", stack.items);
1502 }
1503
1504 #[test]
1505 fn stack_store_load_works() {
1506 #[track_caller]
1507 fn check_value(value: RcStackValue) {
1508 let mut b = CellBuilder::new();
1509 value
1510 .store_as_stack_value(&mut b, Cell::empty_context())
1511 .unwrap();
1512 let parsed = Stack::load_stack_value(&mut b.as_full_slice()).unwrap();
1513
1514 let value = format!("{}", value.display_list());
1515 let parsed = format!("{}", parsed.display_list());
1516 println!("VALUE: {value}, PARSED: {parsed}");
1517 assert_eq!(value, parsed);
1518 }
1519
1520 check_value(SafeRc::new_dyn_value(()));
1522
1523 for negate in [false, true] {
1525 for pow in 0..=256 {
1526 let mut value: BigInt = (BigInt::from(1) << pow) - 1;
1527 if negate {
1528 value = -value;
1529 }
1530 check_value(SafeRc::new_dyn_value(value));
1531 }
1532 }
1533
1534 check_value(SafeRc::new_dyn_value(NaN));
1536
1537 check_value(SafeRc::new_dyn_value(
1539 CellBuilder::build_from((
1540 0x123123u32,
1541 HashBytes::wrap(&[0xff; 32]),
1542 Cell::default(),
1543 Cell::default(),
1544 ))
1545 .unwrap(),
1546 ));
1547
1548 check_value(SafeRc::new_dyn_value({
1550 let cell = CellBuilder::build_from((
1551 0x123123u32,
1552 HashBytes::wrap(&[0xff; 32]),
1553 Cell::default(),
1554 Cell::default(),
1555 ))
1556 .unwrap();
1557 let mut cs = OwnedCellSlice::new_allow_exotic(cell);
1558
1559 {
1560 let mut slice = cs.apply();
1561 slice.skip_first(16, 1).unwrap();
1562 slice.skip_last(8, 0).unwrap();
1563 cs.set_range(slice.range());
1564 }
1565
1566 cs
1567 }));
1568
1569 check_value(SafeRc::new_dyn_value({
1571 let mut b = CellBuilder::new();
1572 b.set_exotic(true);
1573 b.store_u32(0x123123).unwrap();
1574 b.store_u256(HashBytes::wrap(&[0xff; 32])).unwrap();
1575 b.store_reference(Cell::default()).unwrap();
1576 b
1577 }));
1578
1579 check_value(SafeRc::new_dyn_value(tuple![]));
1581 check_value(SafeRc::new_dyn_value(tuple![int 0, int 1, int 2]));
1582 check_value(SafeRc::new_dyn_value(
1583 tuple![int 0, int 1, int 2, [int 1, [int 2, [int 3, int 4]]]],
1584 ));
1585 check_value(SafeRc::new_dyn_value(tuple![
1586 raw SafeRc::new_dyn_value(Cell::default()),
1587 raw SafeRc::new_dyn_value(CellBuilder::new()),
1588 null,
1589 nan,
1590 ]));
1591 }
1592}