capnweb_server/
server_wire_handler.rs1use capnweb_core::{PropertyKey, WireExpression};
5use serde_json::Value;
6use std::collections::HashMap;
7use tracing::{debug, warn};
8
9pub fn wire_expr_to_values(expr: &WireExpression) -> Vec<Value> {
11 match expr {
12 WireExpression::Array(items) => items.iter().map(wire_expr_to_value).collect(),
13 single => vec![wire_expr_to_value(single)],
14 }
15}
16
17pub fn wire_expr_to_values_with_evaluation(
19 expr: &WireExpression,
20 results: &HashMap<i64, WireExpression>,
21) -> Vec<Value> {
22 match expr {
23 WireExpression::Array(items) => items
24 .iter()
25 .map(|e| wire_expr_to_value_with_evaluation(e, results))
26 .collect(),
27 single => vec![wire_expr_to_value_with_evaluation(single, results)],
28 }
29}
30
31pub fn wire_expr_to_value(expr: &WireExpression) -> Value {
33 match expr {
34 WireExpression::Null => Value::Null,
35 WireExpression::Bool(b) => Value::Bool(*b),
36 WireExpression::Number(n) => Value::Number(n.clone()),
37 WireExpression::String(s) => Value::String(s.clone()),
38 WireExpression::Array(items) => {
39 Value::Array(items.iter().map(wire_expr_to_value).collect())
40 }
41 WireExpression::Object(map) => Value::Object(
42 map.iter()
43 .map(|(k, v)| (k.clone(), wire_expr_to_value(v)))
44 .collect(),
45 ),
46 WireExpression::CapRef(id) => {
47 serde_json::json!({
50 "_type": "capability",
51 "id": id
52 })
53 }
54 _ => {
55 warn!("Unsupported WireExpression type: {:?}", expr);
56 Value::String(format!("Unsupported: {:?}", expr))
57 }
58 }
59}
60
61pub fn wire_expr_to_value_with_evaluation(
63 expr: &WireExpression,
64 results: &HashMap<i64, WireExpression>,
65) -> Value {
66 match expr {
67 WireExpression::Pipeline {
69 import_id,
70 property_path,
71 args: _,
72 } => {
73 debug!(
74 "Evaluating pipeline: import_id={}, path={:?}",
75 import_id, property_path
76 );
77
78 if let Some(result_expr) = results.get(import_id) {
80 debug!(
81 "Found result for import_id {}: {:?}",
82 import_id, result_expr
83 );
84
85 if let Some(path) = property_path {
87 let result_value = wire_expr_to_value(result_expr);
88 navigate_property_path(&result_value, path)
89 } else {
90 wire_expr_to_value(result_expr)
92 }
93 } else {
94 warn!(
95 "No result found for import_id {} during pipeline evaluation",
96 import_id
97 );
98 Value::Null
99 }
100 }
101 other => wire_expr_to_value(other),
103 }
104}
105
106fn navigate_property_path(value: &Value, path: &[PropertyKey]) -> Value {
108 let mut current = value.clone();
109
110 for key in path {
111 match key {
112 PropertyKey::String(s) => {
113 if let Value::Object(map) = current {
114 current = map.get(s).cloned().unwrap_or(Value::Null);
115 } else {
116 return Value::Null;
117 }
118 }
119 PropertyKey::Number(n) => {
120 if let Value::Array(arr) = current {
121 let index = *n; current = arr.get(index).cloned().unwrap_or(Value::Null);
123 } else {
124 return Value::Null;
125 }
126 }
127 }
128 }
129
130 current
131}
132
133pub fn value_to_wire_expr(value: Value) -> WireExpression {
135 match value {
136 Value::Null => WireExpression::Null,
137 Value::Bool(b) => WireExpression::Bool(b),
138 Value::Number(n) => WireExpression::Number(n),
139 Value::String(s) => WireExpression::String(s),
140 Value::Array(items) => {
141 WireExpression::Array(items.into_iter().map(value_to_wire_expr).collect())
142 }
143 Value::Object(map) => {
144 if let (Some(type_val), Some(id_val)) = (map.get("_type"), map.get("id")) {
146 if type_val.as_str() == Some("capability") {
147 if let Some(id) = id_val.as_i64() {
148 return WireExpression::CapRef(id);
149 }
150 }
151 }
152
153 WireExpression::Object(
155 map.into_iter()
156 .map(|(k, v)| (k, value_to_wire_expr(v)))
157 .collect(),
158 )
159 }
160 }
161}