1use arbitrary::{Arbitrary, Result, Unstructured};
2use chia_bls::{G1Element, G2Element};
3use clvmr::{Allocator, NodePtr, SExp};
4
5enum Op {
6 Pair(bool),
7 SubTree,
8}
9
10#[derive(Clone, Copy, Debug, PartialEq, Eq, Arbitrary)]
11pub enum ValueKind {
12 Program,
13 Bytes32,
14 SmallInt,
15 G1Point,
16 G2Point,
17 LargeBytes,
18 EnvPath,
19 Tree,
20 Bool,
21 List,
22}
23
24#[derive(Clone, Copy, Debug)]
25pub enum Arity {
26 Nullary,
27 Unary(ValueKind),
28 Binary(ValueKind, ValueKind),
29 Ternary(ValueKind, ValueKind, ValueKind),
30 BinaryOrTernary(ValueKind, ValueKind, ValueKind),
31 Quaternary(ValueKind, ValueKind, ValueKind, ValueKind),
32 Varargs {
33 min: usize,
34 max: usize,
35 arg: ValueKind,
36 },
37 BlsVerify {
38 max_pairs: usize,
39 sig: ValueKind,
40 pk: ValueKind,
41 msg: ValueKind,
42 },
43 BlsPairingIdentity {
44 max_pairs: usize,
45 g1: ValueKind,
46 g2: ValueKind,
47 },
48}
49
50#[derive(Clone, Copy, Debug)]
51struct OpEntry {
52 opcode: u32,
53 arity: Arity,
54 return_kind: ValueKind,
55}
56
57const VARARGS_MAX: usize = 8;
58const MAX_BLS_VERIFY_PAIRS: usize = 4;
59const MAX_BLS_PAIRING_PAIRS: usize = 4;
60
61const PROGRAM_OPS: &[OpEntry] = &[
62 OpEntry {
63 opcode: 2,
64 arity: Arity::Binary(ValueKind::Program, ValueKind::List), return_kind: ValueKind::Tree,
66 },
67 OpEntry {
68 opcode: 3,
69 arity: Arity::Ternary(ValueKind::Bool, ValueKind::Program, ValueKind::Program), return_kind: ValueKind::Program,
71 },
72 OpEntry {
73 opcode: 4,
74 arity: Arity::Binary(ValueKind::Tree, ValueKind::Tree), return_kind: ValueKind::List,
76 },
77 OpEntry {
78 opcode: 5,
79 arity: Arity::Unary(ValueKind::List), return_kind: ValueKind::Tree,
81 },
82 OpEntry {
83 opcode: 6,
84 arity: Arity::Unary(ValueKind::List), return_kind: ValueKind::List,
86 },
87 OpEntry {
88 opcode: 7,
89 arity: Arity::Unary(ValueKind::Tree), return_kind: ValueKind::Bool,
91 },
92 OpEntry {
93 opcode: 8,
94 arity: Arity::Unary(ValueKind::Tree), return_kind: ValueKind::Tree,
96 },
97 OpEntry {
98 opcode: 9,
99 arity: Arity::Binary(ValueKind::LargeBytes, ValueKind::LargeBytes), return_kind: ValueKind::Bool,
101 },
102 OpEntry {
103 opcode: 10,
104 arity: Arity::Binary(ValueKind::LargeBytes, ValueKind::LargeBytes), return_kind: ValueKind::Bool,
106 },
107 OpEntry {
108 opcode: 11,
109 arity: Arity::Varargs {
110 min: 0,
111 max: VARARGS_MAX,
112 arg: ValueKind::LargeBytes,
113 }, return_kind: ValueKind::Bytes32,
115 },
116 OpEntry {
117 opcode: 12,
118 arity: Arity::BinaryOrTernary(
119 ValueKind::LargeBytes,
120 ValueKind::SmallInt,
121 ValueKind::SmallInt,
122 ), return_kind: ValueKind::LargeBytes,
124 },
125 OpEntry {
126 opcode: 13,
127 arity: Arity::Unary(ValueKind::LargeBytes), return_kind: ValueKind::SmallInt,
129 },
130 OpEntry {
131 opcode: 14,
132 arity: Arity::Varargs {
133 min: 0,
134 max: VARARGS_MAX,
135 arg: ValueKind::LargeBytes,
136 }, return_kind: ValueKind::LargeBytes,
138 },
139 OpEntry {
140 opcode: 16,
141 arity: Arity::Varargs {
142 min: 0,
143 max: VARARGS_MAX,
144 arg: ValueKind::SmallInt,
145 }, return_kind: ValueKind::SmallInt,
147 },
148 OpEntry {
149 opcode: 17,
150 arity: Arity::Varargs {
151 min: 0,
152 max: VARARGS_MAX,
153 arg: ValueKind::SmallInt,
154 }, return_kind: ValueKind::SmallInt,
156 },
157 OpEntry {
158 opcode: 18,
159 arity: Arity::Varargs {
160 min: 0,
161 max: VARARGS_MAX,
162 arg: ValueKind::SmallInt,
163 }, return_kind: ValueKind::SmallInt,
165 },
166 OpEntry {
167 opcode: 19,
168 arity: Arity::Binary(ValueKind::SmallInt, ValueKind::SmallInt), return_kind: ValueKind::SmallInt,
170 },
171 OpEntry {
172 opcode: 20,
173 arity: Arity::Binary(ValueKind::SmallInt, ValueKind::SmallInt), return_kind: ValueKind::List,
175 },
176 OpEntry {
177 opcode: 21,
178 arity: Arity::Binary(ValueKind::SmallInt, ValueKind::SmallInt), return_kind: ValueKind::Bool,
180 },
181 OpEntry {
182 opcode: 22,
183 arity: Arity::Binary(ValueKind::SmallInt, ValueKind::SmallInt), return_kind: ValueKind::SmallInt,
185 },
186 OpEntry {
187 opcode: 23,
188 arity: Arity::Binary(ValueKind::SmallInt, ValueKind::SmallInt), return_kind: ValueKind::SmallInt,
190 },
191 OpEntry {
192 opcode: 24,
193 arity: Arity::Varargs {
194 min: 0,
195 max: VARARGS_MAX,
196 arg: ValueKind::SmallInt,
197 }, return_kind: ValueKind::SmallInt,
199 },
200 OpEntry {
201 opcode: 25,
202 arity: Arity::Varargs {
203 min: 0,
204 max: VARARGS_MAX,
205 arg: ValueKind::SmallInt,
206 }, return_kind: ValueKind::SmallInt,
208 },
209 OpEntry {
210 opcode: 26,
211 arity: Arity::Varargs {
212 min: 0,
213 max: VARARGS_MAX,
214 arg: ValueKind::SmallInt,
215 }, return_kind: ValueKind::SmallInt,
217 },
218 OpEntry {
219 opcode: 27,
220 arity: Arity::Unary(ValueKind::SmallInt), return_kind: ValueKind::SmallInt,
222 },
223 OpEntry {
224 opcode: 29,
225 arity: Arity::Varargs {
226 min: 0,
227 max: VARARGS_MAX,
228 arg: ValueKind::G1Point,
229 }, return_kind: ValueKind::G1Point,
231 },
232 OpEntry {
233 opcode: 30,
234 arity: Arity::Unary(ValueKind::SmallInt), return_kind: ValueKind::G1Point,
236 },
237 OpEntry {
238 opcode: 32,
239 arity: Arity::Unary(ValueKind::Bool), return_kind: ValueKind::Bool,
241 },
242 OpEntry {
243 opcode: 33,
244 arity: Arity::Varargs {
245 min: 0,
246 max: VARARGS_MAX,
247 arg: ValueKind::Bool,
248 }, return_kind: ValueKind::Bool,
250 },
251 OpEntry {
252 opcode: 34,
253 arity: Arity::Varargs {
254 min: 0,
255 max: VARARGS_MAX,
256 arg: ValueKind::Bool,
257 }, return_kind: ValueKind::Bool,
259 },
260 OpEntry {
261 opcode: 36,
262 arity: Arity::Quaternary(
263 ValueKind::SmallInt,
264 ValueKind::SmallInt,
265 ValueKind::Program,
266 ValueKind::Tree,
267 ), return_kind: ValueKind::Tree,
269 },
270 OpEntry {
271 opcode: 48,
272 arity: Arity::Ternary(ValueKind::Bytes32, ValueKind::Bytes32, ValueKind::SmallInt), return_kind: ValueKind::Bytes32,
274 },
275 OpEntry {
276 opcode: 49,
277 arity: Arity::Varargs {
278 min: 0,
279 max: VARARGS_MAX,
280 arg: ValueKind::G1Point,
281 }, return_kind: ValueKind::G1Point,
283 },
284 OpEntry {
285 opcode: 50,
286 arity: Arity::Binary(ValueKind::G1Point, ValueKind::SmallInt), return_kind: ValueKind::G1Point,
288 },
289 OpEntry {
290 opcode: 51,
291 arity: Arity::Unary(ValueKind::G1Point), return_kind: ValueKind::G1Point,
293 },
294 OpEntry {
295 opcode: 52,
296 arity: Arity::Varargs {
297 min: 0,
298 max: VARARGS_MAX,
299 arg: ValueKind::G2Point,
300 }, return_kind: ValueKind::G2Point,
302 },
303 OpEntry {
304 opcode: 53,
305 arity: Arity::Varargs {
306 min: 0,
307 max: VARARGS_MAX,
308 arg: ValueKind::G2Point,
309 }, return_kind: ValueKind::G2Point,
311 },
312 OpEntry {
313 opcode: 54,
314 arity: Arity::Binary(ValueKind::G2Point, ValueKind::SmallInt), return_kind: ValueKind::G2Point,
316 },
317 OpEntry {
318 opcode: 55,
319 arity: Arity::Unary(ValueKind::G2Point), return_kind: ValueKind::G2Point,
321 },
322 OpEntry {
323 opcode: 56,
324 arity: Arity::Varargs {
325 min: 1,
326 max: 2,
327 arg: ValueKind::LargeBytes,
328 }, return_kind: ValueKind::G1Point,
330 },
331 OpEntry {
332 opcode: 57,
333 arity: Arity::Varargs {
334 min: 1,
335 max: 2,
336 arg: ValueKind::LargeBytes,
337 }, return_kind: ValueKind::G2Point,
339 },
340 OpEntry {
341 opcode: 58,
342 arity: Arity::BlsPairingIdentity {
343 max_pairs: MAX_BLS_PAIRING_PAIRS,
344 g1: ValueKind::G1Point,
345 g2: ValueKind::G2Point,
346 },
347 return_kind: ValueKind::Bool,
348 },
349 OpEntry {
350 opcode: 59,
351 arity: Arity::BlsVerify {
352 max_pairs: MAX_BLS_VERIFY_PAIRS,
353 sig: ValueKind::G2Point,
354 pk: ValueKind::G1Point,
355 msg: ValueKind::LargeBytes,
356 },
357 return_kind: ValueKind::Bool,
358 },
359 OpEntry {
360 opcode: 60,
361 arity: Arity::Ternary(
362 ValueKind::SmallInt,
363 ValueKind::SmallInt,
364 ValueKind::SmallInt,
365 ), return_kind: ValueKind::SmallInt,
367 },
368 OpEntry {
369 opcode: 61,
370 arity: Arity::Binary(ValueKind::SmallInt, ValueKind::SmallInt), return_kind: ValueKind::SmallInt,
372 },
373 OpEntry {
374 opcode: 62,
375 arity: Arity::Varargs {
376 min: 0,
377 max: VARARGS_MAX,
378 arg: ValueKind::LargeBytes,
379 }, return_kind: ValueKind::Bytes32,
381 },
382 OpEntry {
383 opcode: 63,
384 arity: Arity::Unary(ValueKind::Tree), return_kind: ValueKind::Bytes32,
386 },
387 OpEntry {
388 opcode: 0x13d61f00,
389 arity: Arity::Ternary(
390 ValueKind::LargeBytes,
391 ValueKind::Bytes32,
392 ValueKind::LargeBytes,
393 ),
394 return_kind: ValueKind::Bool,
395 },
396 OpEntry {
397 opcode: 0x1c3a8f00,
398 arity: Arity::Ternary(
399 ValueKind::LargeBytes,
400 ValueKind::Bytes32,
401 ValueKind::LargeBytes,
402 ),
403 return_kind: ValueKind::Bool,
404 },
405];
406
407#[derive(Arbitrary)]
408enum NodeType {
409 Pair,
410 Bytes,
411 U8,
412 U16,
413 U32,
414 Previous,
415}
416
417#[derive(Debug)]
418pub struct ArbitraryClvmTree<const MAX_NODES: i64 = 600_000, const REUSE_NODES: bool = true> {
419 pub allocator: Allocator,
420 pub tree: NodePtr,
421 pub num_nodes: u32,
422}
423
424impl<'a, const MAX_NODES: i64, const REUSE_NODES: bool> Arbitrary<'a>
425 for ArbitraryClvmTree<MAX_NODES, REUSE_NODES>
426{
427 fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
428 let mut a = Allocator::new();
429 let (tree, num_nodes) =
430 make_tree_limits(&mut a, u, MAX_NODES, REUSE_NODES).expect("make_tree");
431 Ok(Self {
432 allocator: a,
433 tree,
434 num_nodes,
435 })
436 }
437}
438
439pub fn make_tree(a: &mut Allocator, unstructured: &mut Unstructured<'_>) -> (NodePtr, u32) {
440 make_tree_limits(a, unstructured, 600_000, true).expect("out of memory")
441}
442
443fn arity_args(
444 unstructured: &mut Unstructured<'_>,
445 arity: &Arity,
446) -> anyhow::Result<Vec<ValueKind>> {
447 Ok(match *arity {
448 Arity::Nullary => Vec::new(),
449 Arity::Unary(kind) => vec![kind],
450 Arity::Binary(k0, k1) => vec![k0, k1],
451 Arity::Ternary(k0, k1, k2) => vec![k0, k1, k2],
452 Arity::BinaryOrTernary(k0, k1, k2) => {
453 let argc = unstructured.int_in_range(2..=3)?;
454 if argc == 2 {
455 vec![k0, k1]
456 } else {
457 vec![k0, k1, k2]
458 }
459 }
460 Arity::Quaternary(k0, k1, k2, k3) => vec![k0, k1, k2, k3],
461 Arity::Varargs { min, max, arg } => {
462 let argc = unstructured.int_in_range(min..=max)?;
463 vec![arg; argc]
464 }
465 Arity::BlsVerify {
466 max_pairs,
467 sig,
468 pk,
469 msg,
470 } => {
471 let pairs = unstructured.int_in_range(0..=max_pairs)?;
472 let mut args = Vec::with_capacity(1 + pairs * 2);
473 args.push(sig);
474 for _ in 0..pairs {
475 args.push(pk);
476 args.push(msg);
477 }
478 args
479 }
480 Arity::BlsPairingIdentity { max_pairs, g1, g2 } => {
481 let pairs = unstructured.int_in_range(0..=max_pairs)?;
482 let mut args = Vec::with_capacity(pairs * 2);
483 for _ in 0..pairs {
484 args.push(g1);
485 args.push(g2);
486 }
487 args
488 }
489 })
490}
491
492fn pick_op_by_return_kind(
493 unstructured: &mut Unstructured<'_>,
494 kind: ValueKind,
495) -> anyhow::Result<Option<OpEntry>> {
496 let mut matches = Vec::new();
497 for entry in PROGRAM_OPS {
498 if entry.return_kind == kind {
499 matches.push(*entry);
500 }
501 }
502 if matches.is_empty() {
503 Ok(None)
504 } else {
505 Ok(Some(*unstructured.choose(&matches)?))
506 }
507}
508
509fn pick_env_path(
510 a: &Allocator,
511 unstructured: &mut Unstructured<'_>,
512 env: NodePtr,
513) -> anyhow::Result<u64> {
514 if unstructured.ratio(1, 64)? {
515 return Ok(unstructured.arbitrary::<u64>()?);
516 }
517
518 let mut stack = Vec::new();
519 stack.push((env, 1u64, 0u32));
520 let mut chosen: Option<u64> = None;
521 let mut count: usize = 0;
522
523 while let Some((node, path, depth)) = stack.pop() {
524 count = count.saturating_add(1);
525 if unstructured.int_in_range(1..=count)? == 1 {
526 chosen = Some(path);
527 }
528
529 if depth >= 63 {
530 continue;
531 }
532
533 if let SExp::Pair(left, right) = a.sexp(node) {
534 let base_bits = if depth == 0 {
535 0
536 } else {
537 path & ((1u64 << depth) - 1)
538 };
539 let next_depth = depth + 1;
540 let terminator = 1u64 << next_depth;
541 let left_path = base_bits | terminator;
542 let right_path = base_bits | (1u64 << depth) | terminator;
543 stack.push((left, left_path, next_depth));
544 stack.push((right, right_path, next_depth));
545 }
546 }
547
548 Ok(chosen.unwrap_or_else(|| unstructured.arbitrary::<u64>().unwrap_or(1)))
549}
550
551fn make_list_value(
552 a: &mut Allocator,
553 unstructured: &mut Unstructured<'_>,
554 env: NodePtr,
555 max_nodes: i64,
556) -> anyhow::Result<NodePtr> {
557 let length = unstructured.int_in_range(0..=4)?;
558 let base_nodes = length as i64;
559 let available = (max_nodes - base_nodes).max(0);
560 let per_item_budget = if length == 0 {
561 0
562 } else {
563 (available / length as i64).max(0)
564 };
565
566 let mut list = a.nil();
567 for _ in 0..length {
568 let item = make_value(a, unstructured, ValueKind::Tree, env, env, per_item_budget)?;
569 list = a.new_pair(item, list)?;
570 }
571 Ok(list)
572}
573
574fn make_literal_value(
575 a: &mut Allocator,
576 unstructured: &mut Unstructured<'_>,
577 kind: ValueKind,
578 env: NodePtr,
579 inner_env: NodePtr,
580 max_nodes: i64,
581) -> anyhow::Result<NodePtr> {
582 let value = match kind {
583 ValueKind::Program => make_clvm_program(a, unstructured, inner_env, max_nodes)?,
584 ValueKind::Bytes32 => a.new_atom(unstructured.bytes(32)?)?,
585 ValueKind::G1Point => {
586 if unstructured.ratio(1, 16)? {
587 a.new_atom(unstructured.bytes(48)?)?
588 } else {
589 a.new_g1(G1Element::arbitrary(unstructured)?)?
590 }
591 }
592 ValueKind::G2Point => {
593 if unstructured.ratio(1, 16)? {
594 a.new_atom(unstructured.bytes(96)?)?
595 } else {
596 a.new_g2(G2Element::arbitrary(unstructured)?)?
597 }
598 }
599 ValueKind::LargeBytes => {
600 let len = unstructured.int_in_range(64..=128)?;
601 a.new_atom(unstructured.bytes(len)?)?
602 }
603 ValueKind::EnvPath => {
604 let val = pick_env_path(a, unstructured, env)?;
607 return Ok(a.new_number(val.into())?);
608 }
609 ValueKind::SmallInt => {
610 let val: u8 = unstructured.arbitrary()?;
611 a.new_number(val.into())?
612 }
613 ValueKind::Bool => *unstructured.choose(&[a.nil(), a.one()])?,
614 ValueKind::List => make_list_value(a, unstructured, env, max_nodes)?,
615 ValueKind::Tree => make_tree_limits(a, unstructured, max_nodes, true)?.0,
616 };
617 let quote = a.one();
618 Ok(a.new_pair(quote, value)?)
619}
620
621fn make_value(
622 a: &mut Allocator,
623 unstructured: &mut Unstructured<'_>,
624 mut kind: ValueKind,
625 env: NodePtr,
626 inner_env: NodePtr,
627 max_nodes: i64,
628) -> anyhow::Result<NodePtr> {
629 if unstructured.ratio(1, 32)? {
631 let kind: ValueKind = unstructured.arbitrary()?;
632 return make_literal_value(a, unstructured, kind, env, inner_env, max_nodes);
633 }
634 if unstructured.ratio(1, 16)? {
636 kind = ValueKind::EnvPath;
637 }
638
639 if unstructured.ratio(1, 2)?
641 && let Some(entry) = pick_op_by_return_kind(unstructured, kind)?
642 {
643 make_program_with_entry(a, unstructured, entry, env, max_nodes)
644 } else {
645 make_literal_value(a, unstructured, kind, env, inner_env, max_nodes)
646 }
647}
648
649fn make_program_with_entry(
650 a: &mut Allocator,
651 unstructured: &mut Unstructured<'_>,
652 entry: OpEntry,
653 env: NodePtr,
654 max_nodes: i64,
655) -> anyhow::Result<NodePtr> {
656 let args_kinds = arity_args(unstructured, &entry.arity)?;
657 let n = args_kinds.len();
658 let base_nodes = 2 + n;
659 if max_nodes < base_nodes as i64 {
660 return Ok(a.one());
661 }
662 let available = max_nodes - base_nodes as i64;
663 let arg_budget = if n == 0 {
664 0
665 } else {
666 (available / n as i64).max(0)
667 };
668
669 let apply_like = entry.opcode == 2 || entry.opcode == 36;
670
671 let mut args = NodePtr::NIL;
672 for kind in args_kinds.iter().rev() {
673 let inner_env = if apply_like && *kind == ValueKind::Program {
674 args
678 } else {
679 env
680 };
681 let arg = make_value(a, unstructured, *kind, env, inner_env, arg_budget)?;
682 args = a.new_pair(arg, args)?;
683 }
684
685 let op_atom = a.new_number(entry.opcode.into())?;
686 Ok(a.new_pair(op_atom, args)?)
687}
688
689pub fn make_clvm_program(
690 a: &mut Allocator,
691 unstructured: &mut Unstructured<'_>,
692 env: NodePtr,
693 max_nodes: i64,
694) -> anyhow::Result<NodePtr> {
695 if unstructured.ratio(1, 64)? {
696 return Ok(make_tree_limits(a, unstructured, max_nodes, false)?.0);
697 }
698
699 let entry = *unstructured.choose(PROGRAM_OPS)?;
700 make_program_with_entry(a, unstructured, entry, env, max_nodes)
701}
702
703pub fn make_tree_limits(
706 a: &mut Allocator,
707 unstructured: &mut Unstructured<'_>,
708 mut max_nodes: i64,
709 reuse_nodes: bool,
710) -> anyhow::Result<(NodePtr, u32)> {
711 let mut previous_nodes = Vec::new();
712 let mut value_stack = Vec::new();
713 let mut op_stack = vec![Op::SubTree];
714 let mut sub_trees: i64 = 1;
716 let mut counter = 0;
717
718 while let Some(op) = op_stack.pop() {
719 match op {
720 Op::Pair(swap) => {
721 let left = value_stack.pop().expect("internal error, empty stack");
722 let right = value_stack.pop().expect("internal error, empty stack");
723 let pair = if swap {
724 a.new_pair(left, right)?
725 } else {
726 a.new_pair(right, left)?
727 };
728 counter += 1;
729 value_stack.push(pair);
730 previous_nodes.push(pair);
731 }
732 Op::SubTree => {
733 sub_trees -= 1;
734 if unstructured.is_empty() {
735 value_stack.push(NodePtr::NIL);
736 continue;
737 }
738 match unstructured.arbitrary::<NodeType>() {
739 Err(..) => value_stack.push(NodePtr::NIL),
740 Ok(NodeType::Pair) => {
741 if sub_trees > unstructured.len() as i64 || max_nodes <= 0 {
742 value_stack.push(if reuse_nodes {
745 *unstructured
746 .choose(&previous_nodes)
747 .unwrap_or(&NodePtr::NIL)
748 } else {
749 NodePtr::NIL
750 });
751 } else {
752 let swap = unstructured.arbitrary::<bool>() == Ok(true);
756 op_stack.push(Op::Pair(swap));
757 op_stack.push(Op::SubTree);
758 op_stack.push(Op::SubTree);
759 sub_trees += 2;
760 max_nodes -= 2;
761 }
762 }
763 Ok(NodeType::Bytes) => {
764 counter += 1;
765 value_stack.push(match unstructured.arbitrary::<Vec<u8>>() {
766 Err(..) => NodePtr::NIL,
767 Ok(val) => {
768 let node = a.new_atom(&val)?;
769 previous_nodes.push(node);
770 node
771 }
772 });
773 }
774 Ok(NodeType::U8) => {
775 counter += 1;
776 value_stack.push(match unstructured.arbitrary::<u8>() {
777 Err(..) => NodePtr::NIL,
778 Ok(val) => a.new_small_number(val.into())?,
779 });
780 }
781 Ok(NodeType::U16) => {
782 counter += 1;
783 value_stack.push(match unstructured.arbitrary::<u16>() {
784 Err(..) => NodePtr::NIL,
785 Ok(val) => a.new_small_number(val.into())?,
786 });
787 }
788 Ok(NodeType::U32) => {
789 counter += 1;
790 value_stack.push(match unstructured.arbitrary::<u32>() {
791 Err(..) => NodePtr::NIL,
792 Ok(val) => a.new_number(val.into())?,
793 });
794 }
795 Ok(NodeType::Previous) => {
796 value_stack.push(if reuse_nodes {
797 *unstructured
798 .choose(&previous_nodes)
799 .unwrap_or(&NodePtr::NIL)
800 } else {
801 NodePtr::NIL
802 });
803 }
804 }
805 }
806 }
807 }
808 assert_eq!(value_stack.len(), 1);
809 Ok((value_stack.remove(0), counter))
810}
811
812pub fn make_list(a: &mut Allocator, unstructured: &mut Unstructured<'_>) -> NodePtr {
813 let mut ret = NodePtr::NIL;
814
815 let length = unstructured.arbitrary::<u8>().unwrap_or(0);
816 let nil_terminated = unstructured.arbitrary::<bool>().unwrap_or(false);
817
818 for _ in 0..length {
819 let value = match unstructured
820 .arbitrary::<NodeType>()
821 .unwrap_or(NodeType::Previous)
822 {
823 NodeType::U8 => a
824 .new_small_number(unstructured.arbitrary::<u8>().unwrap_or(0).into())
825 .unwrap(),
826
827 NodeType::U16 => a
828 .new_small_number(unstructured.arbitrary::<u16>().unwrap_or(0).into())
829 .unwrap(),
830
831 NodeType::U32 => a
832 .new_number(unstructured.arbitrary::<u32>().unwrap_or(0).into())
833 .unwrap(),
834
835 NodeType::Bytes => a
836 .new_atom(&unstructured.arbitrary::<Vec<u8>>().unwrap_or_default())
837 .unwrap(),
838
839 NodeType::Pair => {
840 let left = NodePtr::NIL;
841 let right = NodePtr::NIL;
842 a.new_pair(left, right).unwrap()
843 }
844
845 NodeType::Previous => NodePtr::NIL,
846 };
847
848 ret = if nil_terminated {
849 a.new_pair(value, ret).unwrap()
850 } else {
851 value
852 };
853 }
854
855 ret
856}