use capnweb_core::{PropertyKey, WireExpression};
use serde_json::Value;
use std::collections::HashMap;
use tracing::{debug, warn};
pub fn wire_expr_to_values(expr: &WireExpression) -> Vec<Value> {
match expr {
WireExpression::Array(items) => items.iter().map(wire_expr_to_value).collect(),
single => vec![wire_expr_to_value(single)],
}
}
pub fn wire_expr_to_values_with_evaluation(
expr: &WireExpression,
results: &HashMap<i64, WireExpression>,
) -> Vec<Value> {
match expr {
WireExpression::Array(items) => items
.iter()
.map(|e| wire_expr_to_value_with_evaluation(e, results))
.collect(),
single => vec![wire_expr_to_value_with_evaluation(single, results)],
}
}
pub fn wire_expr_to_value(expr: &WireExpression) -> Value {
match expr {
WireExpression::Null => Value::Null,
WireExpression::Bool(b) => Value::Bool(*b),
WireExpression::Number(n) => Value::Number(n.clone()),
WireExpression::String(s) => Value::String(s.clone()),
WireExpression::Array(items) => {
Value::Array(items.iter().map(wire_expr_to_value).collect())
}
WireExpression::Object(map) => Value::Object(
map.iter()
.map(|(k, v)| (k.clone(), wire_expr_to_value(v)))
.collect(),
),
WireExpression::CapRef(id) => {
serde_json::json!({
"_type": "capability",
"id": id
})
}
_ => {
warn!("Unsupported WireExpression type: {:?}", expr);
Value::String(format!("Unsupported: {:?}", expr))
}
}
}
pub fn wire_expr_to_value_with_evaluation(
expr: &WireExpression,
results: &HashMap<i64, WireExpression>,
) -> Value {
match expr {
WireExpression::Pipeline {
import_id,
property_path,
args: _,
} => {
debug!(
"Evaluating pipeline: import_id={}, path={:?}",
import_id, property_path
);
if let Some(result_expr) = results.get(import_id) {
debug!(
"Found result for import_id {}: {:?}",
import_id, result_expr
);
if let Some(path) = property_path {
let result_value = wire_expr_to_value(result_expr);
navigate_property_path(&result_value, path)
} else {
wire_expr_to_value(result_expr)
}
} else {
warn!(
"No result found for import_id {} during pipeline evaluation",
import_id
);
Value::Null
}
}
other => wire_expr_to_value(other),
}
}
fn navigate_property_path(value: &Value, path: &[PropertyKey]) -> Value {
let mut current = value.clone();
for key in path {
match key {
PropertyKey::String(s) => {
if let Value::Object(map) = current {
current = map.get(s).cloned().unwrap_or(Value::Null);
} else {
return Value::Null;
}
}
PropertyKey::Number(n) => {
if let Value::Array(arr) = current {
let index = *n; current = arr.get(index).cloned().unwrap_or(Value::Null);
} else {
return Value::Null;
}
}
}
}
current
}
pub fn value_to_wire_expr(value: Value) -> WireExpression {
match value {
Value::Null => WireExpression::Null,
Value::Bool(b) => WireExpression::Bool(b),
Value::Number(n) => WireExpression::Number(n),
Value::String(s) => WireExpression::String(s),
Value::Array(items) => {
WireExpression::Array(items.into_iter().map(value_to_wire_expr).collect())
}
Value::Object(map) => {
if let (Some(type_val), Some(id_val)) = (map.get("_type"), map.get("id")) {
if type_val.as_str() == Some("capability") {
if let Some(id) = id_val.as_i64() {
return WireExpression::CapRef(id);
}
}
}
WireExpression::Object(
map.into_iter()
.map(|(k, v)| (k, value_to_wire_expr(v)))
.collect(),
)
}
}
}