1use crate::stack::{Stack, pop, push};
7use crate::value::Value;
8use std::sync::Arc;
9
10#[unsafe(no_mangle)]
17pub unsafe extern "C" fn patch_seq_variant_field_count(stack: Stack) -> Stack {
18 unsafe {
19 let (stack, value) = pop(stack);
20
21 match value {
22 Value::Variant(variant_data) => {
23 let count = variant_data.fields.len() as i64;
24 push(stack, Value::Int(count))
25 }
26 _ => panic!("variant-field-count: expected Variant, got {:?}", value),
27 }
28 }
29}
30
31#[unsafe(no_mangle)]
38pub unsafe extern "C" fn patch_seq_variant_tag(stack: Stack) -> Stack {
39 unsafe {
40 let (stack, value) = pop(stack);
41
42 match value {
43 Value::Variant(variant_data) => {
44 let tag = variant_data.tag as i64;
45 push(stack, Value::Int(tag))
46 }
47 _ => panic!("variant-tag: expected Variant, got {:?}", value),
48 }
49 }
50}
51
52#[unsafe(no_mangle)]
63pub unsafe extern "C" fn patch_seq_variant_field_at(stack: Stack) -> Stack {
64 unsafe {
65 let (stack, index_val) = pop(stack);
66 let index = match index_val {
67 Value::Int(i) => i,
68 _ => panic!(
69 "variant-field-at: expected Int (index), got {:?}",
70 index_val
71 ),
72 };
73
74 if index < 0 {
75 panic!("variant-field-at: index cannot be negative: {}", index);
76 }
77
78 let (stack, variant_val) = pop(stack);
79
80 match variant_val {
81 Value::Variant(variant_data) => {
82 let idx = index as usize;
83 if idx >= variant_data.fields.len() {
84 panic!(
85 "variant-field-at: index {} out of bounds (variant has {} fields)",
86 index,
87 variant_data.fields.len()
88 );
89 }
90
91 let field = variant_data.fields[idx].clone();
93 push(stack, field)
94 }
95 _ => panic!("variant-field-at: expected Variant, got {:?}", variant_val),
96 }
97 }
98}
99
100#[unsafe(no_mangle)]
111pub unsafe extern "C" fn patch_seq_make_variant_0(stack: Stack) -> Stack {
112 use crate::value::VariantData;
113
114 unsafe {
115 let (stack, tag_val) = pop(stack);
116 let tag = match tag_val {
117 Value::Int(t) => {
118 if t < 0 {
119 panic!("make-variant-0: tag cannot be negative: {}", t);
120 }
121 t as u32
122 }
123 _ => panic!("make-variant-0: expected Int (tag), got {:?}", tag_val),
124 };
125
126 let variant = Value::Variant(Arc::new(VariantData::new(tag, vec![])));
127 push(stack, variant)
128 }
129}
130
131#[unsafe(no_mangle)]
138pub unsafe extern "C" fn patch_seq_make_variant_1(stack: Stack) -> Stack {
139 use crate::value::VariantData;
140
141 unsafe {
142 let (stack, tag_val) = pop(stack);
143 let tag = match tag_val {
144 Value::Int(t) => {
145 if t < 0 {
146 panic!("make-variant-1: tag cannot be negative: {}", t);
147 }
148 t as u32
149 }
150 _ => panic!("make-variant-1: expected Int (tag), got {:?}", tag_val),
151 };
152
153 let (stack, field1) = pop(stack);
154 let variant = Value::Variant(Arc::new(VariantData::new(tag, vec![field1])));
155 push(stack, variant)
156 }
157}
158
159#[unsafe(no_mangle)]
166pub unsafe extern "C" fn patch_seq_make_variant_2(stack: Stack) -> Stack {
167 use crate::value::VariantData;
168
169 unsafe {
170 let (stack, tag_val) = pop(stack);
171 let tag = match tag_val {
172 Value::Int(t) => {
173 if t < 0 {
174 panic!("make-variant-2: tag cannot be negative: {}", t);
175 }
176 t as u32
177 }
178 _ => panic!("make-variant-2: expected Int (tag), got {:?}", tag_val),
179 };
180
181 let (stack, field2) = pop(stack);
182 let (stack, field1) = pop(stack);
183 let variant = Value::Variant(Arc::new(VariantData::new(tag, vec![field1, field2])));
184 push(stack, variant)
185 }
186}
187
188#[unsafe(no_mangle)]
195pub unsafe extern "C" fn patch_seq_make_variant_3(stack: Stack) -> Stack {
196 use crate::value::VariantData;
197
198 unsafe {
199 let (stack, tag_val) = pop(stack);
200 let tag = match tag_val {
201 Value::Int(t) => {
202 if t < 0 {
203 panic!("make-variant-3: tag cannot be negative: {}", t);
204 }
205 t as u32
206 }
207 _ => panic!("make-variant-3: expected Int (tag), got {:?}", tag_val),
208 };
209
210 let (stack, field3) = pop(stack);
211 let (stack, field2) = pop(stack);
212 let (stack, field1) = pop(stack);
213 let variant = Value::Variant(Arc::new(VariantData::new(
214 tag,
215 vec![field1, field2, field3],
216 )));
217 push(stack, variant)
218 }
219}
220
221#[unsafe(no_mangle)]
228pub unsafe extern "C" fn patch_seq_make_variant_4(stack: Stack) -> Stack {
229 use crate::value::VariantData;
230
231 unsafe {
232 let (stack, tag_val) = pop(stack);
233 let tag = match tag_val {
234 Value::Int(t) => {
235 if t < 0 {
236 panic!("make-variant-4: tag cannot be negative: {}", t);
237 }
238 t as u32
239 }
240 _ => panic!("make-variant-4: expected Int (tag), got {:?}", tag_val),
241 };
242
243 let (stack, field4) = pop(stack);
244 let (stack, field3) = pop(stack);
245 let (stack, field2) = pop(stack);
246 let (stack, field1) = pop(stack);
247 let variant = Value::Variant(Arc::new(VariantData::new(
248 tag,
249 vec![field1, field2, field3, field4],
250 )));
251 push(stack, variant)
252 }
253}
254
255pub use patch_seq_make_variant_0 as make_variant_0;
257pub use patch_seq_make_variant_1 as make_variant_1;
258pub use patch_seq_make_variant_2 as make_variant_2;
259pub use patch_seq_make_variant_3 as make_variant_3;
260pub use patch_seq_make_variant_4 as make_variant_4;
261
262#[unsafe(no_mangle)]
276pub unsafe extern "C" fn patch_seq_variant_append(stack: Stack) -> Stack {
277 use crate::value::VariantData;
278
279 unsafe {
280 let (stack, value) = pop(stack);
282
283 let (stack, variant_val) = pop(stack);
285
286 match variant_val {
287 Value::Variant(variant_data) => {
288 let mut new_fields = variant_data.fields.to_vec();
290 new_fields.push(value);
291
292 let new_variant =
294 Value::Variant(Arc::new(VariantData::new(variant_data.tag, new_fields)));
295
296 push(stack, new_variant)
297 }
298 _ => panic!("variant-append: expected Variant, got {:?}", variant_val),
299 }
300 }
301}
302
303#[unsafe(no_mangle)]
313pub unsafe extern "C" fn patch_seq_variant_last(stack: Stack) -> Stack {
314 unsafe {
315 let (stack, variant_val) = pop(stack);
316
317 match variant_val {
318 Value::Variant(variant_data) => {
319 if variant_data.fields.is_empty() {
320 panic!("variant-last: variant has no fields");
321 }
322
323 let last = variant_data.fields.last().unwrap().clone();
324 push(stack, last)
325 }
326 _ => panic!("variant-last: expected Variant, got {:?}", variant_val),
327 }
328 }
329}
330
331#[unsafe(no_mangle)]
342pub unsafe extern "C" fn patch_seq_variant_init(stack: Stack) -> Stack {
343 use crate::value::VariantData;
344
345 unsafe {
346 let (stack, variant_val) = pop(stack);
347
348 match variant_val {
349 Value::Variant(variant_data) => {
350 if variant_data.fields.is_empty() {
351 panic!("variant-init: variant has no fields");
352 }
353
354 let new_fields: Vec<Value> =
356 variant_data.fields[..variant_data.fields.len() - 1].to_vec();
357
358 let new_variant =
359 Value::Variant(Arc::new(VariantData::new(variant_data.tag, new_fields)));
360
361 push(stack, new_variant)
362 }
363 _ => panic!("variant-init: expected Variant, got {:?}", variant_val),
364 }
365 }
366}
367
368#[unsafe(no_mangle)]
381pub unsafe extern "C" fn patch_seq_unpack_variant(stack: Stack, field_count: i64) -> Stack {
382 unsafe {
383 let (mut stack, variant_val) = pop(stack);
384
385 match variant_val {
386 Value::Variant(variant_data) => {
387 let count = field_count as usize;
388 if count > variant_data.fields.len() {
389 panic!(
390 "unpack-variant: requested {} fields but variant only has {}",
391 count,
392 variant_data.fields.len()
393 );
394 }
395
396 for i in 0..count {
398 stack = push(stack, variant_data.fields[i].clone());
399 }
400
401 stack
402 }
403 _ => panic!("unpack-variant: expected Variant, got {:?}", variant_val),
404 }
405 }
406}
407
408pub use patch_seq_unpack_variant as unpack_variant;
410pub use patch_seq_variant_append as variant_append;
411pub use patch_seq_variant_field_at as variant_field_at;
412pub use patch_seq_variant_field_count as variant_field_count;
413pub use patch_seq_variant_init as variant_init;
414pub use patch_seq_variant_last as variant_last;
415pub use patch_seq_variant_tag as variant_tag;
416
417#[cfg(test)]
418mod tests {
419 use super::*;
420 use crate::seqstring::global_string;
421 use crate::value::VariantData;
422
423 #[test]
424 fn test_variant_field_count() {
425 unsafe {
426 let variant = Value::Variant(Arc::new(VariantData::new(
428 0,
429 vec![Value::Int(10), Value::Int(20), Value::Int(30)],
430 )));
431
432 let stack = crate::stack::alloc_test_stack();
433 let stack = push(stack, variant);
434 let stack = variant_field_count(stack);
435
436 let (_stack, result) = pop(stack);
437 assert_eq!(result, Value::Int(3));
438 }
439 }
440
441 #[test]
442 fn test_variant_tag() {
443 unsafe {
444 let variant = Value::Variant(Arc::new(VariantData::new(42, vec![Value::Int(10)])));
446
447 let stack = crate::stack::alloc_test_stack();
448 let stack = push(stack, variant);
449 let stack = variant_tag(stack);
450
451 let (_stack, result) = pop(stack);
452 assert_eq!(result, Value::Int(42));
453 }
454 }
455
456 #[test]
457 fn test_variant_field_at() {
458 unsafe {
459 let str1 = global_string("hello".to_string());
460 let str2 = global_string("world".to_string());
461
462 let variant = Value::Variant(Arc::new(VariantData::new(
464 0,
465 vec![
466 Value::String(str1.clone()),
467 Value::Int(42),
468 Value::String(str2.clone()),
469 ],
470 )));
471
472 let stack = crate::stack::alloc_test_stack();
474 let stack = push(stack, variant.clone());
475 let stack = push(stack, Value::Int(0));
476 let stack = variant_field_at(stack);
477
478 let (_stack, result) = pop(stack);
479 assert_eq!(result, Value::String(str1.clone()));
480
481 let stack = push(stack, variant.clone());
483 let stack = push(stack, Value::Int(1));
484 let stack = variant_field_at(stack);
485
486 let (_stack, result) = pop(stack);
487 assert_eq!(result, Value::Int(42));
488
489 let stack = push(stack, variant.clone());
491 let stack = push(stack, Value::Int(2));
492 let stack = variant_field_at(stack);
493
494 let (_stack, result) = pop(stack);
495 assert_eq!(result, Value::String(str2));
496 }
497 }
498
499 #[test]
500 fn test_variant_field_count_empty() {
501 unsafe {
502 let variant = Value::Variant(Arc::new(VariantData::new(0, vec![])));
504
505 let stack = crate::stack::alloc_test_stack();
506 let stack = push(stack, variant);
507 let stack = variant_field_count(stack);
508
509 let (_stack, result) = pop(stack);
510 assert_eq!(result, Value::Int(0));
511 }
512 }
513
514 #[test]
515 fn test_make_variant_with_fields() {
516 unsafe {
517 let stack = crate::stack::alloc_test_stack();
520 let stack = push(stack, Value::Int(10)); let stack = push(stack, Value::Int(20)); let stack = push(stack, Value::Int(30)); let stack = push(stack, Value::Int(42)); let stack = make_variant_3(stack);
526
527 let (_stack, result) = pop(stack);
528
529 match result {
530 Value::Variant(v) => {
531 assert_eq!(v.tag, 42);
532 assert_eq!(v.fields.len(), 3);
533 assert_eq!(v.fields[0], Value::Int(10));
534 assert_eq!(v.fields[1], Value::Int(20));
535 assert_eq!(v.fields[2], Value::Int(30));
536 }
537 _ => panic!("Expected Variant"),
538 }
539 }
540 }
541
542 #[test]
543 fn test_make_variant_empty() {
544 unsafe {
545 let stack = crate::stack::alloc_test_stack();
548 let stack = push(stack, Value::Int(0)); let stack = make_variant_0(stack);
551
552 let (_stack, result) = pop(stack);
553
554 match result {
555 Value::Variant(v) => {
556 assert_eq!(v.tag, 0);
557 assert_eq!(v.fields.len(), 0);
558 }
559 _ => panic!("Expected Variant"),
560 }
561 }
562 }
563
564 #[test]
565 fn test_make_variant_with_mixed_types() {
566 unsafe {
567 let s = global_string("hello".to_string());
568
569 let stack = crate::stack::alloc_test_stack();
571 let stack = push(stack, Value::Int(42));
572 let stack = push(stack, Value::String(s.clone()));
573 let stack = push(stack, Value::Float(3.5));
574 let stack = push(stack, Value::Int(1)); let stack = make_variant_3(stack);
577
578 let (_stack, result) = pop(stack);
579
580 match result {
581 Value::Variant(v) => {
582 assert_eq!(v.tag, 1);
583 assert_eq!(v.fields.len(), 3);
584 assert_eq!(v.fields[0], Value::Int(42));
585 assert_eq!(v.fields[1], Value::String(s));
586 assert_eq!(v.fields[2], Value::Float(3.5));
587 }
588 _ => panic!("Expected Variant"),
589 }
590 }
591 }
592
593 #[test]
594 fn test_variant_append() {
595 unsafe {
596 let stack = crate::stack::alloc_test_stack();
598 let stack = push(stack, Value::Int(4)); let stack = make_variant_0(stack);
600
601 let stack = push(stack, Value::Int(42));
603 let stack = variant_append(stack);
604
605 let (_stack, result) = pop(stack);
607 match result {
608 Value::Variant(v) => {
609 assert_eq!(v.tag, 4);
610 assert_eq!(v.fields.len(), 1);
611 assert_eq!(v.fields[0], Value::Int(42));
612 }
613 _ => panic!("Expected Variant"),
614 }
615 }
616 }
617
618 #[test]
619 fn test_variant_append_multiple() {
620 unsafe {
621 let stack = crate::stack::alloc_test_stack();
623 let stack = push(stack, Value::Int(5)); let stack = make_variant_0(stack);
625
626 let key = global_string("name".to_string());
628 let stack = push(stack, Value::String(key.clone()));
629 let stack = variant_append(stack);
630
631 let val = global_string("John".to_string());
633 let stack = push(stack, Value::String(val.clone()));
634 let stack = variant_append(stack);
635
636 let (_stack, result) = pop(stack);
638 match result {
639 Value::Variant(v) => {
640 assert_eq!(v.tag, 5);
641 assert_eq!(v.fields.len(), 2);
642 assert_eq!(v.fields[0], Value::String(key));
643 assert_eq!(v.fields[1], Value::String(val));
644 }
645 _ => panic!("Expected Variant"),
646 }
647 }
648 }
649
650 #[test]
651 fn test_variant_last() {
652 unsafe {
653 let variant = Value::Variant(Arc::new(VariantData::new(
655 0,
656 vec![Value::Int(10), Value::Int(20), Value::Int(30)],
657 )));
658
659 let stack = crate::stack::alloc_test_stack();
660 let stack = push(stack, variant);
661 let stack = variant_last(stack);
662
663 let (_stack, result) = pop(stack);
664 assert_eq!(result, Value::Int(30));
665 }
666 }
667
668 #[test]
669 fn test_variant_init() {
670 unsafe {
671 let variant = Value::Variant(Arc::new(VariantData::new(
673 42,
674 vec![Value::Int(10), Value::Int(20), Value::Int(30)],
675 )));
676
677 let stack = crate::stack::alloc_test_stack();
678 let stack = push(stack, variant);
679 let stack = variant_init(stack);
680
681 let (_stack, result) = pop(stack);
682 match result {
683 Value::Variant(v) => {
684 assert_eq!(v.tag, 42); assert_eq!(v.fields.len(), 2);
686 assert_eq!(v.fields[0], Value::Int(10));
687 assert_eq!(v.fields[1], Value::Int(20));
688 }
689 _ => panic!("Expected Variant"),
690 }
691 }
692 }
693
694 #[test]
695 fn test_variant_stack_operations() {
696 unsafe {
698 let stack = crate::stack::alloc_test_stack();
700 let stack = push(stack, Value::Int(99)); let stack = make_variant_0(stack);
702
703 let stack = push(stack, Value::Int(10));
705 let stack = variant_append(stack);
706
707 let stack = push(stack, Value::Int(20));
709 let stack = variant_append(stack);
710
711 let (stack, variant) = pop(stack);
714 let stack = push(stack, variant.clone());
715 let stack = push(stack, variant);
716 let stack = variant_last(stack);
717 let (stack, top) = pop(stack);
718 assert_eq!(top, Value::Int(20));
719
720 let stack = variant_init(stack);
722
723 let (stack, variant) = pop(stack);
725 let stack = push(stack, variant.clone());
726 let stack = push(stack, variant);
727 let stack = variant_last(stack);
728 let (stack, top) = pop(stack);
729 assert_eq!(top, Value::Int(10));
730
731 let (_stack, result) = pop(stack);
733 match result {
734 Value::Variant(v) => {
735 assert_eq!(v.fields.len(), 1);
736 assert_eq!(v.fields[0], Value::Int(10));
737 }
738 _ => panic!("Expected Variant"),
739 }
740 }
741 }
742
743 #[test]
744 fn test_variant_clone_is_o1() {
745 let mut variant = Value::Variant(Arc::new(VariantData::new(0, vec![])));
748
749 for i in 0..100 {
751 variant = Value::Variant(Arc::new(VariantData::new(i, vec![variant.clone()])));
752 }
753
754 let start = std::time::Instant::now();
756 for _ in 0..1000 {
757 let _copy = variant.clone();
758 }
759 let elapsed = start.elapsed();
760
761 assert!(
764 elapsed.as_millis() < 10,
765 "Clone took {:?} - should be O(1) with Arc",
766 elapsed
767 );
768 }
769
770 #[test]
771 fn test_variant_arc_sharing() {
772 let inner = Value::Variant(Arc::new(VariantData::new(0, vec![Value::Int(42)])));
774 let outer = Value::Variant(Arc::new(VariantData::new(1, vec![inner.clone()])));
775
776 let outer_clone = outer.clone();
778
779 match (&outer, &outer_clone) {
781 (Value::Variant(a), Value::Variant(b)) => {
782 assert_eq!(a.tag, b.tag);
785 assert_eq!(a.fields.len(), b.fields.len());
786 }
787 _ => panic!("Expected Variants"),
788 }
789 }
790
791 #[test]
792 fn test_variant_thread_safe_sharing() {
793 use std::sync::Arc as StdArc;
796 use std::thread;
797
798 let variant = Value::Variant(Arc::new(VariantData::new(
799 42,
800 vec![Value::Int(1), Value::Int(2), Value::Int(3)],
801 )));
802
803 let shared = StdArc::new(variant);
805
806 let handles: Vec<_> = (0..4)
807 .map(|_| {
808 let v = StdArc::clone(&shared);
809 thread::spawn(move || {
810 match &*v {
812 Value::Variant(data) => {
813 assert_eq!(data.tag, 42);
814 assert_eq!(data.fields.len(), 3);
815 }
816 _ => panic!("Expected Variant"),
817 }
818 })
819 })
820 .collect();
821
822 for h in handles {
823 h.join().expect("Thread panicked");
824 }
825 }
826}