Skip to main content

this_me/kernel/
json.rs

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}