zerokms-protocol 0.12.9

Library to manage the CipherStash ZeroKMS communication protocol
Documentation
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

/// A loose, schema‑free context map that can carry scalars, arrays, and nested maps.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
#[serde(transparent)]
pub struct UnverifiedContext(pub HashMap<String, Option<UnverifiedContextValue>>);

/// Any JSON value we need to handle.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum UnverifiedContextValue {
    Bool(bool),
    I64(i64),
    F64(f64),
    String(String),
    List(Vec<Option<UnverifiedContextValue>>),
    Map(HashMap<String, Option<UnverifiedContextValue>>),
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde_json::json;
    use std::collections::HashMap;

    #[test]
    fn parse_from_json() {
        let raw = r#"
        {
            "flag": true,
            "int": 5,
            "float": 1.23,
            "name": "alice",
            "items": [1, null, false],
            "profile": { "age": 34 }
        }
        "#;

        let ctx: UnverifiedContext = serde_json::from_str(raw).expect("deserialize");

        // Verify a few key fields landed in the right variants
        assert_eq!(
            ctx.0.get("flag"),
            Some(&Some(UnverifiedContextValue::Bool(true)))
        );
        assert_eq!(
            ctx.0.get("int"),
            Some(&Some(UnverifiedContextValue::I64(5)))
        );
        assert_eq!(
            ctx.0.get("float"),
            Some(&Some(UnverifiedContextValue::F64(1.23)))
        );
        assert_eq!(
            ctx.0.get("items"),
            Some(&Some(UnverifiedContextValue::List(vec![
                Some(UnverifiedContextValue::I64(1)),
                None,
                Some(UnverifiedContextValue::Bool(false))
            ])))
        );

        let mut profile = HashMap::new();
        profile.insert("age".to_string(), Some(UnverifiedContextValue::I64(34)));

        assert_eq!(
            ctx.0.get("profile"),
            Some(&Some(UnverifiedContextValue::Map(profile)))
        );
    }

    #[test]
    fn serialise_json() {
        let mut map = HashMap::new();
        map.insert("flag".to_string(), Some(UnverifiedContextValue::Bool(true)));
        map.insert("int".to_string(), Some(UnverifiedContextValue::I64(5)));
        map.insert("float".to_string(), Some(UnverifiedContextValue::F64(1.23)));
        map.insert(
            "name".to_string(),
            Some(UnverifiedContextValue::String("bob".to_string())),
        );
        map.insert(
            "items".to_string(),
            Some(UnverifiedContextValue::List(vec![
                Some(UnverifiedContextValue::I64(1)),
                None,
                Some(UnverifiedContextValue::Bool(false)),
            ])),
        );

        let mut profile = HashMap::new();
        profile.insert("age".to_string(), Some(UnverifiedContextValue::I64(34)));

        map.insert(
            "profile".to_string(),
            Some(UnverifiedContextValue::Map(profile)),
        );

        let ctx = UnverifiedContext(map);

        let json = serde_json::to_value(&ctx).expect("serialise");

        assert_eq!(
            json,
            json!({
                "flag": true,
                "int": 5,
                "float": 1.23,
                "name": "bob",
                "items": [1, null, false],
                "profile": { "age": 34 }
            })
        );
    }
}