1use crate::stack::{Stack, pop, push};
36use crate::value::{MapKey, Value, VariantData};
37use std::sync::Arc;
38
39#[unsafe(no_mangle)]
46pub unsafe extern "C" fn patch_seq_make_map(stack: Stack) -> Stack {
47 unsafe { push(stack, Value::Map(Box::default())) }
48}
49
50#[unsafe(no_mangle)]
61pub unsafe extern "C" fn patch_seq_map_get(stack: Stack) -> Stack {
62 unsafe {
63 let (stack, key_val) = pop(stack);
65 let key = MapKey::from_value(&key_val).unwrap_or_else(|| {
66 panic!(
67 "map-get: key must be Int, String, or Bool, got {:?}",
68 key_val
69 )
70 });
71
72 let (stack, map_val) = pop(stack);
74 let map = match map_val {
75 Value::Map(m) => m,
76 _ => panic!("map-get: expected Map, got {:?}", map_val),
77 };
78
79 match map.get(&key) {
81 Some(value) => {
82 let stack = push(stack, value.clone());
83 push(stack, Value::Bool(true))
84 }
85 None => {
86 let stack = push(stack, Value::Int(0)); push(stack, Value::Bool(false)) }
89 }
90 }
91}
92
93#[unsafe(no_mangle)]
103pub unsafe extern "C" fn patch_seq_map_set(stack: Stack) -> Stack {
104 unsafe {
105 let (stack, value) = pop(stack);
107
108 let (stack, key_val) = pop(stack);
110 let key = MapKey::from_value(&key_val).unwrap_or_else(|| {
111 panic!(
112 "map-set: key must be Int, String, or Bool, got {:?}",
113 key_val
114 )
115 });
116
117 let (stack, map_val) = pop(stack);
119 let mut map = match map_val {
120 Value::Map(m) => *m,
121 _ => panic!("map-set: expected Map, got {:?}", map_val),
122 };
123
124 map.insert(key, value);
126
127 push(stack, Value::Map(Box::new(map)))
128 }
129}
130
131#[unsafe(no_mangle)]
141pub unsafe extern "C" fn patch_seq_map_has(stack: Stack) -> Stack {
142 unsafe {
143 let (stack, key_val) = pop(stack);
145 let key = MapKey::from_value(&key_val).unwrap_or_else(|| {
146 panic!(
147 "map-has?: key must be Int, String, or Bool, got {:?}",
148 key_val
149 )
150 });
151
152 let (stack, map_val) = pop(stack);
154 let map = match map_val {
155 Value::Map(m) => m,
156 _ => panic!("map-has?: expected Map, got {:?}", map_val),
157 };
158
159 let has_key = map.contains_key(&key);
160 push(stack, Value::Bool(has_key))
161 }
162}
163
164#[unsafe(no_mangle)]
175pub unsafe extern "C" fn patch_seq_map_remove(stack: Stack) -> Stack {
176 unsafe {
177 let (stack, key_val) = pop(stack);
179 let key = MapKey::from_value(&key_val).unwrap_or_else(|| {
180 panic!(
181 "map-remove: key must be Int, String, or Bool, got {:?}",
182 key_val
183 )
184 });
185
186 let (stack, map_val) = pop(stack);
188 let mut map = match map_val {
189 Value::Map(m) => *m,
190 _ => panic!("map-remove: expected Map, got {:?}", map_val),
191 };
192
193 map.remove(&key);
195
196 push(stack, Value::Map(Box::new(map)))
197 }
198}
199
200#[unsafe(no_mangle)]
210pub unsafe extern "C" fn patch_seq_map_keys(stack: Stack) -> Stack {
211 unsafe {
212 let (stack, map_val) = pop(stack);
213 let map = match map_val {
214 Value::Map(m) => m,
215 _ => panic!("map-keys: expected Map, got {:?}", map_val),
216 };
217
218 let keys: Vec<Value> = map.keys().map(|k| k.to_value()).collect();
219 let variant = Value::Variant(Arc::new(VariantData::new(0, keys)));
220 push(stack, variant)
221 }
222}
223
224#[unsafe(no_mangle)]
234pub unsafe extern "C" fn patch_seq_map_values(stack: Stack) -> Stack {
235 unsafe {
236 let (stack, map_val) = pop(stack);
237 let map = match map_val {
238 Value::Map(m) => m,
239 _ => panic!("map-values: expected Map, got {:?}", map_val),
240 };
241
242 let values: Vec<Value> = map.values().cloned().collect();
243 let variant = Value::Variant(Arc::new(VariantData::new(0, values)));
244 push(stack, variant)
245 }
246}
247
248#[unsafe(no_mangle)]
255pub unsafe extern "C" fn patch_seq_map_size(stack: Stack) -> Stack {
256 unsafe {
257 let (stack, map_val) = pop(stack);
258 let map = match map_val {
259 Value::Map(m) => m,
260 _ => panic!("map-size: expected Map, got {:?}", map_val),
261 };
262
263 push(stack, Value::Int(map.len() as i64))
264 }
265}
266
267#[unsafe(no_mangle)]
276pub unsafe extern "C" fn patch_seq_map_empty(stack: Stack) -> Stack {
277 unsafe {
278 let (stack, map_val) = pop(stack);
279 let map = match map_val {
280 Value::Map(m) => m,
281 _ => panic!("map-empty?: expected Map, got {:?}", map_val),
282 };
283
284 let is_empty = map.is_empty();
285 push(stack, Value::Bool(is_empty))
286 }
287}
288
289pub use patch_seq_make_map as make_map;
291pub use patch_seq_map_empty as map_empty;
292pub use patch_seq_map_get as map_get;
293pub use patch_seq_map_has as map_has;
294pub use patch_seq_map_keys as map_keys;
295pub use patch_seq_map_remove as map_remove;
296pub use patch_seq_map_set as map_set;
297pub use patch_seq_map_size as map_size;
298pub use patch_seq_map_values as map_values;
299
300#[cfg(test)]
301mod tests {
302 use super::*;
303
304 #[test]
305 fn test_make_map() {
306 unsafe {
307 let stack = crate::stack::alloc_test_stack();
308 let stack = make_map(stack);
309
310 let (_stack, result) = pop(stack);
311 match result {
312 Value::Map(m) => assert!(m.is_empty()),
313 _ => panic!("Expected Map"),
314 }
315 }
316 }
317
318 #[test]
319 fn test_map_set_and_get() {
320 unsafe {
321 let stack = crate::stack::alloc_test_stack();
322 let stack = make_map(stack);
323 let stack = push(stack, Value::String("name".into()));
324 let stack = push(stack, Value::String("Alice".into()));
325 let stack = map_set(stack);
326
327 let stack = push(stack, Value::String("name".into()));
329 let stack = map_get(stack);
330
331 let (stack, flag) = pop(stack);
333 assert_eq!(flag, Value::Bool(true));
334 let (_stack, result) = pop(stack);
335 match result {
336 Value::String(s) => assert_eq!(s.as_str(), "Alice"),
337 _ => panic!("Expected String"),
338 }
339 }
340 }
341
342 #[test]
343 fn test_map_set_with_int_key() {
344 unsafe {
345 let stack = crate::stack::alloc_test_stack();
346 let stack = make_map(stack);
347 let stack = push(stack, Value::Int(42));
348 let stack = push(stack, Value::String("answer".into()));
349 let stack = map_set(stack);
350
351 let stack = push(stack, Value::Int(42));
352 let stack = map_get(stack);
353
354 let (stack, flag) = pop(stack);
356 assert_eq!(flag, Value::Bool(true));
357 let (_stack, result) = pop(stack);
358 match result {
359 Value::String(s) => assert_eq!(s.as_str(), "answer"),
360 _ => panic!("Expected String"),
361 }
362 }
363 }
364
365 #[test]
366 fn test_map_has() {
367 unsafe {
368 let stack = crate::stack::alloc_test_stack();
369 let stack = make_map(stack);
370 let stack = push(stack, Value::String("key".into()));
371 let stack = push(stack, Value::Int(100));
372 let stack = map_set(stack);
373
374 let stack = crate::stack::dup(stack);
376 let stack = push(stack, Value::String("key".into()));
377 let stack = map_has(stack);
378 let (stack, result) = pop(stack);
379 assert_eq!(result, Value::Bool(true));
380
381 let stack = push(stack, Value::String("missing".into()));
383 let stack = map_has(stack);
384 let (_stack, result) = pop(stack);
385 assert_eq!(result, Value::Bool(false));
386 }
387 }
388
389 #[test]
390 fn test_map_remove() {
391 unsafe {
392 let stack = crate::stack::alloc_test_stack();
393 let stack = make_map(stack);
394 let stack = push(stack, Value::String("a".into()));
395 let stack = push(stack, Value::Int(1));
396 let stack = map_set(stack);
397 let stack = push(stack, Value::String("b".into()));
398 let stack = push(stack, Value::Int(2));
399 let stack = map_set(stack);
400
401 let stack = push(stack, Value::String("a".into()));
403 let stack = map_remove(stack);
404
405 let stack = crate::stack::dup(stack);
407 let stack = push(stack, Value::String("a".into()));
408 let stack = map_has(stack);
409 let (stack, result) = pop(stack);
410 assert_eq!(result, Value::Bool(false));
411
412 let stack = push(stack, Value::String("b".into()));
414 let stack = map_has(stack);
415 let (_stack, result) = pop(stack);
416 assert_eq!(result, Value::Bool(true));
417 }
418 }
419
420 #[test]
421 fn test_map_size() {
422 unsafe {
423 let stack = crate::stack::alloc_test_stack();
424 let stack = make_map(stack);
425
426 let stack = map_size(stack);
428 let (stack, result) = pop(stack);
429 assert_eq!(result, Value::Int(0));
430
431 let stack = make_map(stack);
433 let stack = push(stack, Value::String("a".into()));
434 let stack = push(stack, Value::Int(1));
435 let stack = map_set(stack);
436 let stack = push(stack, Value::String("b".into()));
437 let stack = push(stack, Value::Int(2));
438 let stack = map_set(stack);
439
440 let stack = map_size(stack);
441 let (_stack, result) = pop(stack);
442 assert_eq!(result, Value::Int(2));
443 }
444 }
445
446 #[test]
447 fn test_map_empty() {
448 unsafe {
449 let stack = crate::stack::alloc_test_stack();
450 let stack = make_map(stack);
451
452 let stack = map_empty(stack);
453 let (stack, result) = pop(stack);
454 assert_eq!(result, Value::Bool(true));
455
456 let stack = make_map(stack);
458 let stack = push(stack, Value::String("key".into()));
459 let stack = push(stack, Value::Int(1));
460 let stack = map_set(stack);
461
462 let stack = map_empty(stack);
463 let (_stack, result) = pop(stack);
464 assert_eq!(result, Value::Bool(false));
465 }
466 }
467
468 #[test]
469 fn test_map_keys_and_values() {
470 unsafe {
471 let stack = crate::stack::alloc_test_stack();
472 let stack = make_map(stack);
473 let stack = push(stack, Value::String("x".into()));
474 let stack = push(stack, Value::Int(10));
475 let stack = map_set(stack);
476 let stack = push(stack, Value::String("y".into()));
477 let stack = push(stack, Value::Int(20));
478 let stack = map_set(stack);
479
480 let stack = crate::stack::dup(stack); let stack = map_keys(stack);
483 let (stack, keys_result) = pop(stack);
484 match keys_result {
485 Value::Variant(v) => {
486 assert_eq!(v.fields.len(), 2);
487 }
489 _ => panic!("Expected Variant"),
490 }
491
492 let stack = map_values(stack);
494 let (_stack, values_result) = pop(stack);
495 match values_result {
496 Value::Variant(v) => {
497 assert_eq!(v.fields.len(), 2);
498 }
500 _ => panic!("Expected Variant"),
501 }
502 }
503 }
504
505 #[test]
506 fn test_map_get_found() {
507 unsafe {
508 let stack = crate::stack::alloc_test_stack();
509 let stack = make_map(stack);
510 let stack = push(stack, Value::String("key".into()));
511 let stack = push(stack, Value::Int(42));
512 let stack = map_set(stack);
513
514 let stack = push(stack, Value::String("key".into()));
515 let stack = map_get(stack);
516
517 let (stack, flag) = pop(stack);
518 let (_stack, value) = pop(stack);
519 assert_eq!(flag, Value::Bool(true));
520 assert_eq!(value, Value::Int(42));
521 }
522 }
523
524 #[test]
525 fn test_map_get_not_found() {
526 unsafe {
527 let stack = crate::stack::alloc_test_stack();
528 let stack = make_map(stack);
529
530 let stack = push(stack, Value::String("missing".into()));
531 let stack = map_get(stack);
532
533 let (stack, flag) = pop(stack);
534 let (_stack, _value) = pop(stack); assert_eq!(flag, Value::Bool(false));
536 }
537 }
538
539 #[test]
540 fn test_map_with_bool_key() {
541 unsafe {
542 let stack = crate::stack::alloc_test_stack();
543 let stack = make_map(stack);
544 let stack = push(stack, Value::Bool(true));
545 let stack = push(stack, Value::String("yes".into()));
546 let stack = map_set(stack);
547 let stack = push(stack, Value::Bool(false));
548 let stack = push(stack, Value::String("no".into()));
549 let stack = map_set(stack);
550
551 let stack = push(stack, Value::Bool(true));
552 let stack = map_get(stack);
553 let (stack, flag) = pop(stack);
555 assert_eq!(flag, Value::Bool(true));
556 let (_stack, result) = pop(stack);
557 match result {
558 Value::String(s) => assert_eq!(s.as_str(), "yes"),
559 _ => panic!("Expected String"),
560 }
561 }
562 }
563
564 #[test]
565 fn test_map_key_overwrite() {
566 unsafe {
568 let stack = crate::stack::alloc_test_stack();
569 let stack = make_map(stack);
570
571 let stack = push(stack, Value::String("key".into()));
573 let stack = push(stack, Value::Int(100));
574 let stack = map_set(stack);
575
576 let stack = push(stack, Value::String("key".into()));
578 let stack = push(stack, Value::Int(200));
579 let stack = map_set(stack);
580
581 let stack = crate::stack::dup(stack);
583 let stack = map_size(stack);
584 let (stack, size) = pop(stack);
585 assert_eq!(size, Value::Int(1));
586
587 let stack = push(stack, Value::String("key".into()));
589 let stack = map_get(stack);
590 let (stack, flag) = pop(stack);
592 assert_eq!(flag, Value::Bool(true));
593 let (_stack, result) = pop(stack);
594 assert_eq!(result, Value::Int(200));
595 }
596 }
597
598 #[test]
599 fn test_map_mixed_key_types() {
600 unsafe {
602 let stack = crate::stack::alloc_test_stack();
603 let stack = make_map(stack);
604
605 let stack = push(stack, Value::String("name".into()));
607 let stack = push(stack, Value::String("Alice".into()));
608 let stack = map_set(stack);
609
610 let stack = push(stack, Value::Int(42));
612 let stack = push(stack, Value::String("answer".into()));
613 let stack = map_set(stack);
614
615 let stack = push(stack, Value::Bool(true));
617 let stack = push(stack, Value::String("yes".into()));
618 let stack = map_set(stack);
619
620 let stack = crate::stack::dup(stack);
622 let stack = map_size(stack);
623 let (stack, size) = pop(stack);
624 assert_eq!(size, Value::Int(3));
625
626 let stack = crate::stack::dup(stack);
629 let stack = push(stack, Value::String("name".into()));
630 let stack = map_get(stack);
631 let (stack, flag) = pop(stack);
632 assert_eq!(flag, Value::Bool(true));
633 let (stack, result) = pop(stack);
634 match result {
635 Value::String(s) => assert_eq!(s.as_str(), "Alice"),
636 _ => panic!("Expected String for name key"),
637 }
638
639 let stack = crate::stack::dup(stack);
640 let stack = push(stack, Value::Int(42));
641 let stack = map_get(stack);
642 let (stack, flag) = pop(stack);
643 assert_eq!(flag, Value::Bool(true));
644 let (stack, result) = pop(stack);
645 match result {
646 Value::String(s) => assert_eq!(s.as_str(), "answer"),
647 _ => panic!("Expected String for int key"),
648 }
649
650 let stack = push(stack, Value::Bool(true));
651 let stack = map_get(stack);
652 let (stack, flag) = pop(stack);
653 assert_eq!(flag, Value::Bool(true));
654 let (_stack, result) = pop(stack);
655 match result {
656 Value::String(s) => assert_eq!(s.as_str(), "yes"),
657 _ => panic!("Expected String for bool key"),
658 }
659 }
660 }
661}