1use std::collections::BTreeMap;
2use std::fmt;
3
4use serde_json::{Map, Value as JsonValue};
5
6use super::{
7 ExecuteValue, ExplainInput, ExplainOrigin, ExplainResult, InspectMemory, InspectResult,
8 IntoPath, KernelEvent, Memory, OperatorDefinition, Path, ProofResult, RecomputeMode, Snapshot,
9 StoredWrappedKey, Value,
10};
11
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub enum JsonCodecError {
14 InvalidJson(String),
15 ExpectedObject(&'static str),
16 ExpectedArray(&'static str),
17 ExpectedString(&'static str),
18 ExpectedFiniteNumber,
19 MissingField(&'static str),
20 InvalidPath(String),
21}
22
23impl fmt::Display for JsonCodecError {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 match self {
26 Self::InvalidJson(error) => write!(f, "invalid JSON: {error}"),
27 Self::ExpectedObject(field) => write!(f, "{field} must be an object"),
28 Self::ExpectedArray(field) => write!(f, "{field} must be an array"),
29 Self::ExpectedString(field) => write!(f, "{field} must be a string"),
30 Self::ExpectedFiniteNumber => write!(f, "numbers must be finite"),
31 Self::MissingField(field) => write!(f, "missing required field: {field}"),
32 Self::InvalidPath(path) => write!(f, "invalid path: {path}"),
33 }
34 }
35}
36
37impl std::error::Error for JsonCodecError {}
38
39pub fn parse_kernel_value(input: &str) -> Result<Value, JsonCodecError> {
40 let json = serde_json::from_str::<JsonValue>(input)
41 .map_err(|error| JsonCodecError::InvalidJson(error.to_string()))?;
42 kernel_value_from_json(&json)
43}
44
45pub fn kernel_value_to_json(value: &Value) -> JsonValue {
46 match value {
47 Value::Null => JsonValue::Null,
48 Value::Bool(value) => JsonValue::Bool(*value),
49 Value::Number(value) => serde_json::Number::from_f64(*value)
50 .map(JsonValue::Number)
51 .unwrap_or(JsonValue::Null),
52 Value::String(value) => JsonValue::String(value.clone()),
53 Value::Array(values) => JsonValue::Array(values.iter().map(kernel_value_to_json).collect()),
54 Value::Object(values) => JsonValue::Object(
55 values
56 .iter()
57 .map(|(key, value)| (key.clone(), kernel_value_to_json(value)))
58 .collect(),
59 ),
60 Value::Pointer(path) => {
61 JsonValue::Object(Map::from_iter([("__ptr".to_string(), path_to_json(path))]))
62 }
63 Value::Identity(id) => JsonValue::Object(Map::from_iter([(
64 "__id".to_string(),
65 JsonValue::String(id.clone()),
66 )])),
67 }
68}
69
70pub fn kernel_value_from_json(raw: &JsonValue) -> Result<Value, JsonCodecError> {
71 match raw {
72 JsonValue::Null => Ok(Value::Null),
73 JsonValue::Bool(value) => Ok(Value::Bool(*value)),
74 JsonValue::Number(value) => value
75 .as_f64()
76 .filter(|value| value.is_finite())
77 .map(Value::Number)
78 .ok_or(JsonCodecError::ExpectedFiniteNumber),
79 JsonValue::String(value) => Ok(Value::String(value.clone())),
80 JsonValue::Array(values) => values
81 .iter()
82 .map(kernel_value_from_json)
83 .collect::<Result<Vec<_>, _>>()
84 .map(Value::Array),
85 JsonValue::Object(values) => {
86 if values.len() == 1 {
87 if let Some(raw_path) = values.get("__ptr") {
88 return path_from_json(raw_path, "__ptr").map(Value::Pointer);
89 }
90 if let Some(raw_id) = values.get("__id") {
91 return raw_id
92 .as_str()
93 .map(|id| Value::Identity(id.to_string()))
94 .ok_or(JsonCodecError::ExpectedString("__id"));
95 }
96 }
97
98 values
99 .iter()
100 .map(|(key, value)| Ok((key.clone(), kernel_value_from_json(value)?)))
101 .collect::<Result<BTreeMap<_, _>, JsonCodecError>>()
102 .map(Value::Object)
103 }
104 }
105}
106
107pub fn execute_value_to_json(value: &ExecuteValue) -> JsonValue {
108 match value {
109 ExecuteValue::None => JsonValue::Null,
110 ExecuteValue::Value(value) => kernel_value_to_json(value),
111 ExecuteValue::Memories(memories) => {
112 JsonValue::Array(memories.iter().map(memory_to_json).collect())
113 }
114 ExecuteValue::Events(events) => {
115 JsonValue::Array(events.iter().map(kernel_event_to_json).collect())
116 }
117 ExecuteValue::Snapshot(snapshot) => snapshot_to_json(snapshot),
118 ExecuteValue::Inspect(inspect) => inspect_to_json(inspect),
119 ExecuteValue::Explain(explain) => explain_to_json(explain),
120 ExecuteValue::Mode(mode) => JsonValue::String(recompute_mode_to_string(*mode).to_string()),
121 ExecuteValue::KeySpaceManifest(manifest) => keyspaces_to_json(manifest),
122 ExecuteValue::WrappedKey(value) => kernel_value_to_json(value),
123 ExecuteValue::WrappedKeyWrite {
124 envelope,
125 recipient_key_id,
126 } => JsonValue::Object(Map::from_iter([
127 ("envelope".to_string(), kernel_value_to_json(envelope)),
128 (
129 "recipientKeyId".to_string(),
130 optional_string_to_json(recipient_key_id.as_deref()),
131 ),
132 ])),
133 ExecuteValue::WrappedKeyOpenOptions {
134 recipient_key_id,
135 recipient_private_key,
136 output,
137 } => JsonValue::Object(Map::from_iter([
138 (
139 "recipientKeyId".to_string(),
140 optional_string_to_json(recipient_key_id.as_deref()),
141 ),
142 (
143 "recipientPrivateKey".to_string(),
144 recipient_private_key
145 .as_ref()
146 .map(|key| bytes_to_json(&key.to_bytes()))
147 .unwrap_or(JsonValue::Null),
148 ),
149 (
150 "output".to_string(),
151 JsonValue::String(format!("{output:?}")),
152 ),
153 ])),
154 ExecuteValue::RecipientPrivateKey(bytes) | ExecuteValue::Bytes(bytes) => {
155 bytes_to_json(bytes)
156 }
157 }
158}
159
160pub fn kernel_event_to_json(event: &KernelEvent) -> JsonValue {
161 JsonValue::Object(Map::from_iter([
162 ("path".to_string(), path_to_json(&event.path)),
163 (
164 "operator".to_string(),
165 optional_string_to_json(event.operator.as_deref()),
166 ),
167 (
168 "value".to_string(),
169 event
170 .value
171 .as_ref()
172 .map(kernel_value_to_json)
173 .unwrap_or(JsonValue::Null),
174 ),
175 (
176 "memoryHash".to_string(),
177 JsonValue::String(event.memory_hash.clone()),
178 ),
179 ]))
180}
181
182pub fn proof_result_to_json(proof: &ProofResult) -> JsonValue {
183 JsonValue::Object(Map::from_iter([
184 (
185 "identityHash".to_string(),
186 JsonValue::String(proof.identity_hash.clone()),
187 ),
188 (
189 "expression".to_string(),
190 JsonValue::String(proof.expression.clone()),
191 ),
192 (
193 "namespace".to_string(),
194 JsonValue::String(proof.namespace.clone()),
195 ),
196 (
197 "rootNamespace".to_string(),
198 JsonValue::String(proof.root_namespace.clone()),
199 ),
200 (
201 "publicKey".to_string(),
202 JsonValue::String(proof.public_key.clone()),
203 ),
204 (
205 "message".to_string(),
206 JsonValue::String(proof.message.clone()),
207 ),
208 (
209 "signature".to_string(),
210 JsonValue::String(proof.signature.clone()),
211 ),
212 (
213 "timestamp".to_string(),
214 JsonValue::Number(serde_json::Number::from(proof.timestamp)),
215 ),
216 ]))
217}
218
219pub fn snapshot_to_json(snapshot: &Snapshot) -> JsonValue {
220 JsonValue::Object(Map::from_iter([
221 (
222 "memories".to_string(),
223 JsonValue::Array(snapshot.memories.iter().map(memory_to_json).collect()),
224 ),
225 (
226 "localSecrets".to_string(),
227 string_path_map_to_json(&snapshot.local_secrets, "secret"),
228 ),
229 (
230 "localNoises".to_string(),
231 string_path_map_to_json(&snapshot.local_noises, "noise"),
232 ),
233 (
234 "keySpaces".to_string(),
235 keyspaces_to_json(&snapshot.key_spaces),
236 ),
237 (
238 "operators".to_string(),
239 operators_to_json(&snapshot.operators),
240 ),
241 ]))
242}
243
244pub fn snapshot_from_json(raw: &JsonValue) -> Result<Snapshot, JsonCodecError> {
245 let object = raw
246 .as_object()
247 .ok_or(JsonCodecError::ExpectedObject("snapshot"))?;
248 let memories = object
249 .get("memories")
250 .ok_or(JsonCodecError::MissingField("memories"))?
251 .as_array()
252 .ok_or(JsonCodecError::ExpectedArray("memories"))?
253 .iter()
254 .map(memory_from_json)
255 .collect::<Result<Vec<_>, _>>()?;
256
257 Ok(Snapshot {
258 memories,
259 local_secrets: string_path_map_from_json(object.get("localSecrets"), "localSecrets")?,
260 local_noises: string_path_map_from_json(object.get("localNoises"), "localNoises")?,
261 key_spaces: keyspaces_from_json(object.get("keySpaces"))?,
262 operators: operators_from_json(object.get("operators"))?,
263 })
264}
265
266pub fn memory_to_json(memory: &Memory) -> JsonValue {
267 JsonValue::Object(Map::from_iter([
268 ("path".to_string(), path_to_json(&memory.path)),
269 (
270 "operator".to_string(),
271 optional_string_to_json(memory.operator.as_deref()),
272 ),
273 (
274 "expression".to_string(),
275 memory
276 .expression
277 .as_ref()
278 .map(kernel_value_to_json)
279 .unwrap_or(JsonValue::Null),
280 ),
281 ("value".to_string(), kernel_value_to_json(&memory.value)),
282 (
283 "prevHash".to_string(),
284 optional_string_to_json(memory.prev_hash.as_deref()),
285 ),
286 ("hash".to_string(), JsonValue::String(memory.hash.clone())),
287 ]))
288}
289
290fn memory_from_json(raw: &JsonValue) -> Result<Memory, JsonCodecError> {
291 let object = raw
292 .as_object()
293 .ok_or(JsonCodecError::ExpectedObject("memory"))?;
294 let path = path_from_json(
295 object
296 .get("path")
297 .ok_or(JsonCodecError::MissingField("path"))?,
298 "path",
299 )?;
300 let operator = optional_string_from_json(object.get("operator"), "operator")?;
301 let expression = match object.get("expression") {
302 Some(JsonValue::Null) | None => None,
303 Some(value) => Some(kernel_value_from_json(value)?),
304 };
305 let value = kernel_value_from_json(
306 object
307 .get("value")
308 .ok_or(JsonCodecError::MissingField("value"))?,
309 )?;
310 let prev_hash = optional_string_from_json(object.get("prevHash"), "prevHash")?;
311 let hash = object
312 .get("hash")
313 .and_then(JsonValue::as_str)
314 .ok_or(JsonCodecError::ExpectedString("hash"))?
315 .to_string();
316
317 Ok(Memory {
318 path,
319 operator,
320 expression,
321 value,
322 prev_hash,
323 hash,
324 })
325}
326
327fn inspect_to_json(inspect: &InspectResult) -> JsonValue {
328 JsonValue::Object(Map::from_iter([
329 (
330 "memories".to_string(),
331 JsonValue::Array(
332 inspect
333 .memories
334 .iter()
335 .map(inspect_memory_to_json)
336 .collect(),
337 ),
338 ),
339 ("index".to_string(), path_value_map_to_json(&inspect.index)),
340 (
341 "secretScopes".to_string(),
342 paths_to_json(&inspect.secret_scopes),
343 ),
344 (
345 "noiseScopes".to_string(),
346 paths_to_json(&inspect.noise_scopes),
347 ),
348 (
349 "derivations".to_string(),
350 paths_to_json(&inspect.derivations),
351 ),
352 ]))
353}
354
355fn inspect_memory_to_json(memory: &InspectMemory) -> JsonValue {
356 JsonValue::Object(Map::from_iter([
357 ("path".to_string(), path_to_json(&memory.path)),
358 (
359 "operator".to_string(),
360 optional_string_to_json(memory.operator.as_deref()),
361 ),
362 (
363 "expression".to_string(),
364 memory
365 .expression
366 .as_ref()
367 .map(kernel_value_to_json)
368 .unwrap_or(JsonValue::Null),
369 ),
370 ("value".to_string(), kernel_value_to_json(&memory.value)),
371 (
372 "prevHash".to_string(),
373 optional_string_to_json(memory.prev_hash.as_deref()),
374 ),
375 ("hash".to_string(), JsonValue::String(memory.hash.clone())),
376 ]))
377}
378
379fn explain_to_json(explain: &ExplainResult) -> JsonValue {
380 JsonValue::Object(Map::from_iter([
381 ("path".to_string(), path_to_json(&explain.path)),
382 (
383 "value".to_string(),
384 explain
385 .value
386 .as_ref()
387 .map(kernel_value_to_json)
388 .unwrap_or(JsonValue::Null),
389 ),
390 (
391 "expr".to_string(),
392 optional_string_to_json(explain.expr.as_deref()),
393 ),
394 (
395 "derivation".to_string(),
396 explain
397 .derivation
398 .as_ref()
399 .map(|derivation| {
400 JsonValue::Object(Map::from_iter([
401 (
402 "expression".to_string(),
403 JsonValue::String(derivation.expression.clone()),
404 ),
405 (
406 "inputs".to_string(),
407 JsonValue::Array(
408 derivation
409 .inputs
410 .iter()
411 .map(explain_input_to_json)
412 .collect(),
413 ),
414 ),
415 ]))
416 })
417 .unwrap_or(JsonValue::Null),
418 ),
419 (
420 "meta".to_string(),
421 JsonValue::Object(Map::from_iter([
422 (
423 "dependsOn".to_string(),
424 paths_to_json(&explain.meta.depends_on),
425 ),
426 (
427 "resolvedPath".to_string(),
428 path_to_json(&explain.meta.resolved_path),
429 ),
430 (
431 "pointerChain".to_string(),
432 paths_to_json(&explain.meta.pointer_chain),
433 ),
434 ("secret".to_string(), JsonValue::Bool(explain.meta.secret)),
435 (
436 "k".to_string(),
437 JsonValue::Number(serde_json::Number::from(explain.meta.k)),
438 ),
439 (
440 "recomputed".to_string(),
441 paths_to_json(&explain.meta.recomputed),
442 ),
443 (
444 "sourcePath".to_string(),
445 explain
446 .meta
447 .source_path
448 .as_ref()
449 .map(path_to_json)
450 .unwrap_or(JsonValue::Null),
451 ),
452 ])),
453 ),
454 ]))
455}
456
457fn explain_input_to_json(input: &ExplainInput) -> JsonValue {
458 JsonValue::Object(Map::from_iter([
459 ("label".to_string(), JsonValue::String(input.label.clone())),
460 ("path".to_string(), path_to_json(&input.path)),
461 (
462 "value".to_string(),
463 input
464 .value
465 .as_ref()
466 .map(kernel_value_to_json)
467 .unwrap_or(JsonValue::Null),
468 ),
469 (
470 "origin".to_string(),
471 JsonValue::String(
472 match input.origin {
473 ExplainOrigin::Public => "public",
474 ExplainOrigin::Secret => "secret",
475 }
476 .to_string(),
477 ),
478 ),
479 ("masked".to_string(), JsonValue::Bool(input.masked)),
480 ]))
481}
482
483fn keyspaces_to_json(key_spaces: &BTreeMap<String, StoredWrappedKey>) -> JsonValue {
484 JsonValue::Object(
485 key_spaces
486 .iter()
487 .map(|(key_id, stored)| {
488 (
489 key_id.clone(),
490 JsonValue::Object(Map::from_iter([
491 (
492 "envelope".to_string(),
493 kernel_value_to_json(&stored.envelope),
494 ),
495 (
496 "recipientKeyId".to_string(),
497 optional_string_to_json(stored.recipient_key_id.as_deref()),
498 ),
499 ])),
500 )
501 })
502 .collect(),
503 )
504}
505
506fn keyspaces_from_json(
507 raw: Option<&JsonValue>,
508) -> Result<BTreeMap<String, StoredWrappedKey>, JsonCodecError> {
509 let Some(raw) = raw else {
510 return Ok(BTreeMap::new());
511 };
512 let object = raw
513 .as_object()
514 .ok_or(JsonCodecError::ExpectedObject("keySpaces"))?;
515
516 object
517 .iter()
518 .map(|(key_id, raw)| {
519 let object = raw
520 .as_object()
521 .ok_or(JsonCodecError::ExpectedObject("keySpace"))?;
522 let envelope = kernel_value_from_json(
523 object
524 .get("envelope")
525 .ok_or(JsonCodecError::MissingField("envelope"))?,
526 )?;
527 let recipient_key_id =
528 optional_string_from_json(object.get("recipientKeyId"), "recipientKeyId")?;
529 Ok((
530 key_id.clone(),
531 StoredWrappedKey {
532 envelope,
533 recipient_key_id,
534 },
535 ))
536 })
537 .collect()
538}
539
540fn operators_to_json(operators: &BTreeMap<String, OperatorDefinition>) -> JsonValue {
541 JsonValue::Object(
542 operators
543 .iter()
544 .map(|(operator, definition)| {
545 (
546 operator.clone(),
547 JsonValue::Object(Map::from_iter([(
548 "kind".to_string(),
549 JsonValue::String(definition.kind.clone()),
550 )])),
551 )
552 })
553 .collect(),
554 )
555}
556
557fn operators_from_json(
558 raw: Option<&JsonValue>,
559) -> Result<BTreeMap<String, OperatorDefinition>, JsonCodecError> {
560 let Some(raw) = raw else {
561 return Ok(BTreeMap::new());
562 };
563 let object = raw
564 .as_object()
565 .ok_or(JsonCodecError::ExpectedObject("operators"))?;
566
567 object
568 .iter()
569 .map(|(operator, raw)| {
570 let object = raw
571 .as_object()
572 .ok_or(JsonCodecError::ExpectedObject("operator"))?;
573 let kind = object
574 .get("kind")
575 .and_then(JsonValue::as_str)
576 .ok_or(JsonCodecError::ExpectedString("kind"))?
577 .to_string();
578 Ok((operator.clone(), OperatorDefinition { kind }))
579 })
580 .collect()
581}
582
583fn string_path_map_to_json(paths: &BTreeMap<Path, String>, value_key: &'static str) -> JsonValue {
584 JsonValue::Array(
585 paths
586 .iter()
587 .map(|(path, value)| {
588 JsonValue::Object(Map::from_iter([
589 ("path".to_string(), path_to_json(path)),
590 (value_key.to_string(), JsonValue::String(value.clone())),
591 ]))
592 })
593 .collect(),
594 )
595}
596
597fn string_path_map_from_json(
598 raw: Option<&JsonValue>,
599 field: &'static str,
600) -> Result<BTreeMap<Path, String>, JsonCodecError> {
601 let Some(raw) = raw else {
602 return Ok(BTreeMap::new());
603 };
604 if let Some(object) = raw.as_object() {
605 return object
606 .iter()
607 .map(|(path, value)| {
608 let value = value
609 .as_str()
610 .ok_or(JsonCodecError::ExpectedString(field))?
611 .to_string();
612 Ok((path_from_string(path)?, value))
613 })
614 .collect();
615 }
616
617 let values = raw.as_array().ok_or(JsonCodecError::ExpectedArray(field))?;
618 values
619 .iter()
620 .map(|entry| {
621 let object = entry
622 .as_object()
623 .ok_or(JsonCodecError::ExpectedObject(field))?;
624 let path = path_from_json(
625 object
626 .get("path")
627 .ok_or(JsonCodecError::MissingField("path"))?,
628 "path",
629 )?;
630 let value = object
631 .get("secret")
632 .or_else(|| object.get("noise"))
633 .or_else(|| object.get("value"))
634 .and_then(JsonValue::as_str)
635 .ok_or(JsonCodecError::ExpectedString(field))?
636 .to_string();
637 Ok((path, value))
638 })
639 .collect()
640}
641
642fn path_value_map_to_json(values: &BTreeMap<Path, Value>) -> JsonValue {
643 JsonValue::Object(
644 values
645 .iter()
646 .map(|(path, value)| (path.join("."), kernel_value_to_json(value)))
647 .collect(),
648 )
649}
650
651fn paths_to_json(paths: &[Path]) -> JsonValue {
652 JsonValue::Array(paths.iter().map(path_to_json).collect())
653}
654
655fn path_to_json(path: &Path) -> JsonValue {
656 JsonValue::Array(
657 path.iter()
658 .map(|segment| JsonValue::String(segment.clone()))
659 .collect(),
660 )
661}
662
663fn path_from_json(raw: &JsonValue, field: &'static str) -> Result<Path, JsonCodecError> {
664 match raw {
665 JsonValue::String(value) => path_from_string(value),
666 JsonValue::Array(values) => values
667 .iter()
668 .map(|value| {
669 value
670 .as_str()
671 .map(str::to_string)
672 .ok_or(JsonCodecError::ExpectedString(field))
673 })
674 .collect(),
675 _ => Err(JsonCodecError::ExpectedString(field)),
676 }
677}
678
679fn path_from_string(value: &str) -> Result<Path, JsonCodecError> {
680 value
681 .into_path()
682 .map_err(|_| JsonCodecError::InvalidPath(value.to_string()))
683}
684
685fn optional_string_to_json(value: Option<&str>) -> JsonValue {
686 value
687 .map(|value| JsonValue::String(value.to_string()))
688 .unwrap_or(JsonValue::Null)
689}
690
691fn optional_string_from_json(
692 raw: Option<&JsonValue>,
693 field: &'static str,
694) -> Result<Option<String>, JsonCodecError> {
695 match raw {
696 Some(JsonValue::Null) | None => Ok(None),
697 Some(JsonValue::String(value)) => Ok(Some(value.clone())),
698 Some(_) => Err(JsonCodecError::ExpectedString(field)),
699 }
700}
701
702fn recompute_mode_to_string(mode: RecomputeMode) -> &'static str {
703 match mode {
704 RecomputeMode::Eager => "eager",
705 RecomputeMode::Lazy => "lazy",
706 }
707}
708
709fn bytes_to_json(bytes: &[u8]) -> JsonValue {
710 JsonValue::Array(
711 bytes
712 .iter()
713 .copied()
714 .map(|byte| JsonValue::Number(serde_json::Number::from(byte)))
715 .collect(),
716 )
717}