zerokms_protocol/
unverified_context.rs

1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4/// A loose, schema‑free context map that can carry scalars, arrays, and nested maps.
5#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
6#[serde(transparent)]
7pub struct UnverifiedContext(pub HashMap<String, Option<UnverifiedContextValue>>);
8
9/// Any JSON value we need to handle.
10#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11#[serde(untagged)]
12pub enum UnverifiedContextValue {
13    Bool(bool),
14    I64(i64),
15    F64(f64),
16    String(String),
17    List(Vec<Option<UnverifiedContextValue>>),
18    Map(HashMap<String, Option<UnverifiedContextValue>>),
19}
20
21#[cfg(test)]
22mod tests {
23    use super::*;
24    use serde_json::json;
25    use std::collections::HashMap;
26
27    #[test]
28    fn parse_from_json() {
29        let raw = r#"
30        {
31            "flag": true,
32            "int": 5,
33            "float": 1.23,
34            "name": "alice",
35            "items": [1, null, false],
36            "profile": { "age": 34 }
37        }
38        "#;
39
40        let ctx: UnverifiedContext = serde_json::from_str(raw).expect("deserialize");
41
42        // Verify a few key fields landed in the right variants
43        assert_eq!(
44            ctx.0.get("flag"),
45            Some(&Some(UnverifiedContextValue::Bool(true)))
46        );
47        assert_eq!(
48            ctx.0.get("int"),
49            Some(&Some(UnverifiedContextValue::I64(5)))
50        );
51        assert_eq!(
52            ctx.0.get("float"),
53            Some(&Some(UnverifiedContextValue::F64(1.23)))
54        );
55        assert_eq!(
56            ctx.0.get("items"),
57            Some(&Some(UnverifiedContextValue::List(vec![
58                Some(UnverifiedContextValue::I64(1)),
59                None,
60                Some(UnverifiedContextValue::Bool(false))
61            ])))
62        );
63
64        let mut profile = HashMap::new();
65        profile.insert("age".to_string(), Some(UnverifiedContextValue::I64(34)));
66
67        assert_eq!(
68            ctx.0.get("profile"),
69            Some(&Some(UnverifiedContextValue::Map(profile)))
70        );
71    }
72
73    #[test]
74    fn serialise_json() {
75        let mut map = HashMap::new();
76        map.insert("flag".to_string(), Some(UnverifiedContextValue::Bool(true)));
77        map.insert("int".to_string(), Some(UnverifiedContextValue::I64(5)));
78        map.insert("float".to_string(), Some(UnverifiedContextValue::F64(1.23)));
79        map.insert(
80            "name".to_string(),
81            Some(UnverifiedContextValue::String("bob".to_string())),
82        );
83        map.insert(
84            "items".to_string(),
85            Some(UnverifiedContextValue::List(vec![
86                Some(UnverifiedContextValue::I64(1)),
87                None,
88                Some(UnverifiedContextValue::Bool(false)),
89            ])),
90        );
91
92        let mut profile = HashMap::new();
93        profile.insert("age".to_string(), Some(UnverifiedContextValue::I64(34)));
94
95        map.insert(
96            "profile".to_string(),
97            Some(UnverifiedContextValue::Map(profile)),
98        );
99
100        let ctx = UnverifiedContext(map);
101
102        let json = serde_json::to_value(&ctx).expect("serialise");
103
104        assert_eq!(
105            json,
106            json!({
107                "flag": true,
108                "int": 5,
109                "float": 1.23,
110                "name": "bob",
111                "items": [1, null, false],
112                "profile": { "age": 34 }
113            })
114        );
115    }
116}