1use crate::stack::{Stack, pop, push};
37use crate::value::{MapKey, Value, VariantData};
38use std::sync::Arc;
39
40#[unsafe(no_mangle)]
47pub unsafe extern "C" fn patch_seq_make_map(stack: Stack) -> Stack {
48 unsafe { push(stack, Value::Map(Box::default())) }
49}
50
51#[unsafe(no_mangle)]
60pub unsafe extern "C" fn patch_seq_map_get(stack: Stack) -> Stack {
61 unsafe {
62 let (stack, key_val) = pop(stack);
64 let key = MapKey::from_value(&key_val).unwrap_or_else(|| {
65 panic!(
66 "map-get: key must be Int, String, or Bool, got {:?}",
67 key_val
68 )
69 });
70
71 let (stack, map_val) = pop(stack);
73 let map = match map_val {
74 Value::Map(m) => m,
75 _ => panic!("map-get: expected Map, got {:?}", map_val),
76 };
77
78 let value = map
80 .get(&key)
81 .unwrap_or_else(|| panic!("map-get: key {:?} not found", key))
82 .clone();
83
84 push(stack, value)
85 }
86}
87
88#[unsafe(no_mangle)]
98pub unsafe extern "C" fn patch_seq_map_get_safe(stack: Stack) -> Stack {
99 unsafe {
100 let (stack, key_val) = pop(stack);
102 let key = MapKey::from_value(&key_val).unwrap_or_else(|| {
103 panic!(
104 "map-get-safe: key must be Int, String, or Bool, got {:?}",
105 key_val
106 )
107 });
108
109 let (stack, map_val) = pop(stack);
111 let map = match map_val {
112 Value::Map(m) => m,
113 _ => panic!("map-get-safe: expected Map, got {:?}", map_val),
114 };
115
116 match map.get(&key) {
118 Some(value) => {
119 let stack = push(stack, value.clone());
120 push(stack, Value::Int(1))
121 }
122 None => {
123 let stack = push(stack, Value::Int(0)); push(stack, Value::Int(0)) }
126 }
127 }
128}
129
130#[unsafe(no_mangle)]
140pub unsafe extern "C" fn patch_seq_map_set(stack: Stack) -> Stack {
141 unsafe {
142 let (stack, value) = pop(stack);
144
145 let (stack, key_val) = pop(stack);
147 let key = MapKey::from_value(&key_val).unwrap_or_else(|| {
148 panic!(
149 "map-set: key must be Int, String, or Bool, got {:?}",
150 key_val
151 )
152 });
153
154 let (stack, map_val) = pop(stack);
156 let mut map = match map_val {
157 Value::Map(m) => *m,
158 _ => panic!("map-set: expected Map, got {:?}", map_val),
159 };
160
161 map.insert(key, value);
163
164 push(stack, Value::Map(Box::new(map)))
165 }
166}
167
168#[unsafe(no_mangle)]
178pub unsafe extern "C" fn patch_seq_map_has(stack: Stack) -> Stack {
179 unsafe {
180 let (stack, key_val) = pop(stack);
182 let key = MapKey::from_value(&key_val).unwrap_or_else(|| {
183 panic!(
184 "map-has?: key must be Int, String, or Bool, got {:?}",
185 key_val
186 )
187 });
188
189 let (stack, map_val) = pop(stack);
191 let map = match map_val {
192 Value::Map(m) => m,
193 _ => panic!("map-has?: expected Map, got {:?}", map_val),
194 };
195
196 let has_key = if map.contains_key(&key) { 1i64 } else { 0i64 };
197 push(stack, Value::Int(has_key))
198 }
199}
200
201#[unsafe(no_mangle)]
212pub unsafe extern "C" fn patch_seq_map_remove(stack: Stack) -> Stack {
213 unsafe {
214 let (stack, key_val) = pop(stack);
216 let key = MapKey::from_value(&key_val).unwrap_or_else(|| {
217 panic!(
218 "map-remove: key must be Int, String, or Bool, got {:?}",
219 key_val
220 )
221 });
222
223 let (stack, map_val) = pop(stack);
225 let mut map = match map_val {
226 Value::Map(m) => *m,
227 _ => panic!("map-remove: expected Map, got {:?}", map_val),
228 };
229
230 map.remove(&key);
232
233 push(stack, Value::Map(Box::new(map)))
234 }
235}
236
237#[unsafe(no_mangle)]
247pub unsafe extern "C" fn patch_seq_map_keys(stack: Stack) -> Stack {
248 unsafe {
249 let (stack, map_val) = pop(stack);
250 let map = match map_val {
251 Value::Map(m) => m,
252 _ => panic!("map-keys: expected Map, got {:?}", map_val),
253 };
254
255 let keys: Vec<Value> = map.keys().map(|k| k.to_value()).collect();
256 let variant = Value::Variant(Arc::new(VariantData::new(0, keys)));
257 push(stack, variant)
258 }
259}
260
261#[unsafe(no_mangle)]
271pub unsafe extern "C" fn patch_seq_map_values(stack: Stack) -> Stack {
272 unsafe {
273 let (stack, map_val) = pop(stack);
274 let map = match map_val {
275 Value::Map(m) => m,
276 _ => panic!("map-values: expected Map, got {:?}", map_val),
277 };
278
279 let values: Vec<Value> = map.values().cloned().collect();
280 let variant = Value::Variant(Arc::new(VariantData::new(0, values)));
281 push(stack, variant)
282 }
283}
284
285#[unsafe(no_mangle)]
292pub unsafe extern "C" fn patch_seq_map_size(stack: Stack) -> Stack {
293 unsafe {
294 let (stack, map_val) = pop(stack);
295 let map = match map_val {
296 Value::Map(m) => m,
297 _ => panic!("map-size: expected Map, got {:?}", map_val),
298 };
299
300 push(stack, Value::Int(map.len() as i64))
301 }
302}
303
304#[unsafe(no_mangle)]
313pub unsafe extern "C" fn patch_seq_map_empty(stack: Stack) -> Stack {
314 unsafe {
315 let (stack, map_val) = pop(stack);
316 let map = match map_val {
317 Value::Map(m) => m,
318 _ => panic!("map-empty?: expected Map, got {:?}", map_val),
319 };
320
321 let is_empty = if map.is_empty() { 1i64 } else { 0i64 };
322 push(stack, Value::Int(is_empty))
323 }
324}
325
326pub use patch_seq_make_map as make_map;
328pub use patch_seq_map_empty as map_empty;
329pub use patch_seq_map_get as map_get;
330pub use patch_seq_map_get_safe as map_get_safe;
331pub use patch_seq_map_has as map_has;
332pub use patch_seq_map_keys as map_keys;
333pub use patch_seq_map_remove as map_remove;
334pub use patch_seq_map_set as map_set;
335pub use patch_seq_map_size as map_size;
336pub use patch_seq_map_values as map_values;
337
338#[cfg(test)]
339mod tests {
340 use super::*;
341
342 #[test]
343 fn test_make_map() {
344 unsafe {
345 let stack = crate::stack::alloc_test_stack();
346 let stack = make_map(stack);
347
348 let (_stack, result) = pop(stack);
349 match result {
350 Value::Map(m) => assert!(m.is_empty()),
351 _ => panic!("Expected Map"),
352 }
353 }
354 }
355
356 #[test]
357 fn test_map_set_and_get() {
358 unsafe {
359 let stack = crate::stack::alloc_test_stack();
360 let stack = make_map(stack);
361 let stack = push(stack, Value::String("name".into()));
362 let stack = push(stack, Value::String("Alice".into()));
363 let stack = map_set(stack);
364
365 let stack = push(stack, Value::String("name".into()));
367 let stack = map_get(stack);
368
369 let (_stack, result) = pop(stack);
370 match result {
371 Value::String(s) => assert_eq!(s.as_str(), "Alice"),
372 _ => panic!("Expected String"),
373 }
374 }
375 }
376
377 #[test]
378 fn test_map_set_with_int_key() {
379 unsafe {
380 let stack = crate::stack::alloc_test_stack();
381 let stack = make_map(stack);
382 let stack = push(stack, Value::Int(42));
383 let stack = push(stack, Value::String("answer".into()));
384 let stack = map_set(stack);
385
386 let stack = push(stack, Value::Int(42));
387 let stack = map_get(stack);
388
389 let (_stack, result) = pop(stack);
390 match result {
391 Value::String(s) => assert_eq!(s.as_str(), "answer"),
392 _ => panic!("Expected String"),
393 }
394 }
395 }
396
397 #[test]
398 fn test_map_has() {
399 unsafe {
400 let stack = crate::stack::alloc_test_stack();
401 let stack = make_map(stack);
402 let stack = push(stack, Value::String("key".into()));
403 let stack = push(stack, Value::Int(100));
404 let stack = map_set(stack);
405
406 let stack = crate::stack::dup(stack);
408 let stack = push(stack, Value::String("key".into()));
409 let stack = map_has(stack);
410 let (stack, result) = pop(stack);
411 assert_eq!(result, Value::Int(1));
412
413 let stack = push(stack, Value::String("missing".into()));
415 let stack = map_has(stack);
416 let (_stack, result) = pop(stack);
417 assert_eq!(result, Value::Int(0));
418 }
419 }
420
421 #[test]
422 fn test_map_remove() {
423 unsafe {
424 let stack = crate::stack::alloc_test_stack();
425 let stack = make_map(stack);
426 let stack = push(stack, Value::String("a".into()));
427 let stack = push(stack, Value::Int(1));
428 let stack = map_set(stack);
429 let stack = push(stack, Value::String("b".into()));
430 let stack = push(stack, Value::Int(2));
431 let stack = map_set(stack);
432
433 let stack = push(stack, Value::String("a".into()));
435 let stack = map_remove(stack);
436
437 let stack = crate::stack::dup(stack);
439 let stack = push(stack, Value::String("a".into()));
440 let stack = map_has(stack);
441 let (stack, result) = pop(stack);
442 assert_eq!(result, Value::Int(0));
443
444 let stack = push(stack, Value::String("b".into()));
446 let stack = map_has(stack);
447 let (_stack, result) = pop(stack);
448 assert_eq!(result, Value::Int(1));
449 }
450 }
451
452 #[test]
453 fn test_map_size() {
454 unsafe {
455 let stack = crate::stack::alloc_test_stack();
456 let stack = make_map(stack);
457
458 let stack = map_size(stack);
460 let (stack, result) = pop(stack);
461 assert_eq!(result, Value::Int(0));
462
463 let stack = make_map(stack);
465 let stack = push(stack, Value::String("a".into()));
466 let stack = push(stack, Value::Int(1));
467 let stack = map_set(stack);
468 let stack = push(stack, Value::String("b".into()));
469 let stack = push(stack, Value::Int(2));
470 let stack = map_set(stack);
471
472 let stack = map_size(stack);
473 let (_stack, result) = pop(stack);
474 assert_eq!(result, Value::Int(2));
475 }
476 }
477
478 #[test]
479 fn test_map_empty() {
480 unsafe {
481 let stack = crate::stack::alloc_test_stack();
482 let stack = make_map(stack);
483
484 let stack = map_empty(stack);
485 let (stack, result) = pop(stack);
486 assert_eq!(result, Value::Int(1));
487
488 let stack = make_map(stack);
490 let stack = push(stack, Value::String("key".into()));
491 let stack = push(stack, Value::Int(1));
492 let stack = map_set(stack);
493
494 let stack = map_empty(stack);
495 let (_stack, result) = pop(stack);
496 assert_eq!(result, Value::Int(0));
497 }
498 }
499
500 #[test]
501 fn test_map_keys_and_values() {
502 unsafe {
503 let stack = crate::stack::alloc_test_stack();
504 let stack = make_map(stack);
505 let stack = push(stack, Value::String("x".into()));
506 let stack = push(stack, Value::Int(10));
507 let stack = map_set(stack);
508 let stack = push(stack, Value::String("y".into()));
509 let stack = push(stack, Value::Int(20));
510 let stack = map_set(stack);
511
512 let stack = crate::stack::dup(stack); let stack = map_keys(stack);
515 let (stack, keys_result) = pop(stack);
516 match keys_result {
517 Value::Variant(v) => {
518 assert_eq!(v.fields.len(), 2);
519 }
521 _ => panic!("Expected Variant"),
522 }
523
524 let stack = map_values(stack);
526 let (_stack, values_result) = pop(stack);
527 match values_result {
528 Value::Variant(v) => {
529 assert_eq!(v.fields.len(), 2);
530 }
532 _ => panic!("Expected Variant"),
533 }
534 }
535 }
536
537 #[test]
538 fn test_map_get_safe_found() {
539 unsafe {
540 let stack = crate::stack::alloc_test_stack();
541 let stack = make_map(stack);
542 let stack = push(stack, Value::String("key".into()));
543 let stack = push(stack, Value::Int(42));
544 let stack = map_set(stack);
545
546 let stack = push(stack, Value::String("key".into()));
547 let stack = map_get_safe(stack);
548
549 let (stack, flag) = pop(stack);
550 let (_stack, value) = pop(stack);
551 assert_eq!(flag, Value::Int(1));
552 assert_eq!(value, Value::Int(42));
553 }
554 }
555
556 #[test]
557 fn test_map_get_safe_not_found() {
558 unsafe {
559 let stack = crate::stack::alloc_test_stack();
560 let stack = make_map(stack);
561
562 let stack = push(stack, Value::String("missing".into()));
563 let stack = map_get_safe(stack);
564
565 let (stack, flag) = pop(stack);
566 let (_stack, _value) = pop(stack); assert_eq!(flag, Value::Int(0));
568 }
569 }
570
571 #[test]
572 fn test_map_with_bool_key() {
573 unsafe {
574 let stack = crate::stack::alloc_test_stack();
575 let stack = make_map(stack);
576 let stack = push(stack, Value::Bool(true));
577 let stack = push(stack, Value::String("yes".into()));
578 let stack = map_set(stack);
579 let stack = push(stack, Value::Bool(false));
580 let stack = push(stack, Value::String("no".into()));
581 let stack = map_set(stack);
582
583 let stack = push(stack, Value::Bool(true));
584 let stack = map_get(stack);
585 let (_stack, result) = pop(stack);
586 match result {
587 Value::String(s) => assert_eq!(s.as_str(), "yes"),
588 _ => panic!("Expected String"),
589 }
590 }
591 }
592
593 #[test]
594 fn test_map_key_overwrite() {
595 unsafe {
597 let stack = crate::stack::alloc_test_stack();
598 let stack = make_map(stack);
599
600 let stack = push(stack, Value::String("key".into()));
602 let stack = push(stack, Value::Int(100));
603 let stack = map_set(stack);
604
605 let stack = push(stack, Value::String("key".into()));
607 let stack = push(stack, Value::Int(200));
608 let stack = map_set(stack);
609
610 let stack = crate::stack::dup(stack);
612 let stack = map_size(stack);
613 let (stack, size) = pop(stack);
614 assert_eq!(size, Value::Int(1));
615
616 let stack = push(stack, Value::String("key".into()));
618 let stack = map_get(stack);
619 let (_stack, result) = pop(stack);
620 assert_eq!(result, Value::Int(200));
621 }
622 }
623
624 #[test]
625 fn test_map_mixed_key_types() {
626 unsafe {
628 let stack = crate::stack::alloc_test_stack();
629 let stack = make_map(stack);
630
631 let stack = push(stack, Value::String("name".into()));
633 let stack = push(stack, Value::String("Alice".into()));
634 let stack = map_set(stack);
635
636 let stack = push(stack, Value::Int(42));
638 let stack = push(stack, Value::String("answer".into()));
639 let stack = map_set(stack);
640
641 let stack = push(stack, Value::Bool(true));
643 let stack = push(stack, Value::String("yes".into()));
644 let stack = map_set(stack);
645
646 let stack = crate::stack::dup(stack);
648 let stack = map_size(stack);
649 let (stack, size) = pop(stack);
650 assert_eq!(size, Value::Int(3));
651
652 let stack = crate::stack::dup(stack);
654 let stack = push(stack, Value::String("name".into()));
655 let stack = map_get(stack);
656 let (stack, result) = pop(stack);
657 match result {
658 Value::String(s) => assert_eq!(s.as_str(), "Alice"),
659 _ => panic!("Expected String for name key"),
660 }
661
662 let stack = crate::stack::dup(stack);
663 let stack = push(stack, Value::Int(42));
664 let stack = map_get(stack);
665 let (stack, result) = pop(stack);
666 match result {
667 Value::String(s) => assert_eq!(s.as_str(), "answer"),
668 _ => panic!("Expected String for int key"),
669 }
670
671 let stack = push(stack, Value::Bool(true));
672 let stack = map_get(stack);
673 let (_stack, result) = pop(stack);
674 match result {
675 Value::String(s) => assert_eq!(s.as_str(), "yes"),
676 _ => panic!("Expected String for bool key"),
677 }
678 }
679 }
680}