Skip to main content

akar_function/scalar/
union_funcs.rs

1use super::get_string;
2use crate::registry::*;
3use akar_common::types::Value;
4
5// ==================== Union functions ====================
6
7/// Evaluate a union function.
8pub(crate) fn evaluate_union(op: UnionOp, args: &[Value]) -> Result<Value, String> {
9    match op {
10        UnionOp::UnionValue => {
11            // UNION_VALUE(val) → create a union wrapping the value as a single variant
12            let val = args[0].clone();
13            Ok(Value::Struct(vec![
14                ("tag".to_string(), Value::UInt16(0)),
15                ("_value".to_string(), val),
16            ]))
17        }
18        UnionOp::UnionTag => {
19            // UNION_TAG(union) → return the active tag name as a string
20            let entries = match &args[0] {
21                Value::Struct(entries) => entries,
22                _ => return Err("UNION_TAG requires a union argument".into()),
23            };
24            // Find the tag field (should be first entry)
25            let tag_val = entries
26                .iter()
27                .find(|(k, _)| k == "tag")
28                .ok_or("Union has no tag field".to_string())?;
29            let tag_idx = match &tag_val.1 {
30                Value::UInt16(x) => *x as usize,
31                _ => return Err("Invalid tag field type".into()),
32            };
33            // The active variant name is at entries[tag_idx + 1]
34            let field_idx = tag_idx + 1;
35            if field_idx >= entries.len() {
36                return Err(format!("Union tag index {} out of range", tag_idx));
37            }
38            Ok(Value::String(entries[field_idx].0.clone()))
39        }
40        UnionOp::UnionExtract => {
41            // UNION_EXTRACT(union, key) → same as struct_extract
42            let struct_val = &args[0];
43            let key = get_string(&args[1])?;
44            match struct_val {
45                Value::Struct(entries) => {
46                    for (k, v) in entries {
47                        if *k == key {
48                            return Ok(v.clone());
49                        }
50                    }
51                    Err(format!("Key '{}' not found in union", key))
52                }
53                _ => Err("UNION_EXTRACT requires a union argument".into()),
54            }
55        }
56    }
57}