Skip to main content

acp_runtime/
json_support.rs

1// Copyright 2026 ACP Project
2// Licensed under the Apache License, Version 2.0
3// See LICENSE file for details.
4
5use serde::Serialize;
6use serde::de::DeserializeOwned;
7use serde_json::{Map, Value};
8
9use crate::errors::{AcpError, AcpResult};
10
11pub type JsonMap = Map<String, Value>;
12
13pub fn to_json<T: Serialize>(value: &T) -> AcpResult<String> {
14    serde_json::to_string(value).map_err(AcpError::from)
15}
16
17pub fn from_json<T: DeserializeOwned>(value: &str) -> AcpResult<T> {
18    serde_json::from_str(value).map_err(AcpError::from)
19}
20
21pub fn to_value<T: Serialize>(value: &T) -> AcpResult<Value> {
22    serde_json::to_value(value).map_err(AcpError::from)
23}
24
25pub fn to_map<T: Serialize>(value: &T) -> AcpResult<JsonMap> {
26    match to_value(value)? {
27        Value::Object(map) => Ok(map),
28        _ => Err(AcpError::Validation("expected JSON object".to_string())),
29    }
30}
31
32pub fn value_to_map(value: Value) -> AcpResult<JsonMap> {
33    match value {
34        Value::Object(map) => Ok(map),
35        _ => Err(AcpError::Validation("expected JSON object".to_string())),
36    }
37}
38
39pub fn map_from_json(value: &str) -> AcpResult<JsonMap> {
40    match serde_json::from_str::<Value>(value)? {
41        Value::Object(map) => Ok(map),
42        _ => Err(AcpError::Validation(
43            "unable to parse JSON object".to_string(),
44        )),
45    }
46}
47
48pub fn convert<T: DeserializeOwned>(value: &Value) -> AcpResult<T> {
49    serde_json::from_value(value.clone()).map_err(AcpError::from)
50}
51
52pub fn canonical_json_string(value: &Value) -> AcpResult<String> {
53    let normalized = normalize_json(value);
54    serde_json::to_string(&normalized).map_err(AcpError::from)
55}
56
57pub fn canonical_json_bytes(value: &Value) -> AcpResult<Vec<u8>> {
58    Ok(canonical_json_string(value)?.into_bytes())
59}
60
61fn normalize_json(value: &Value) -> Value {
62    match value {
63        Value::Object(map) => {
64            let mut keys = map.keys().cloned().collect::<Vec<_>>();
65            keys.sort();
66            let mut out = JsonMap::new();
67            for key in keys {
68                if let Some(item) = map.get(&key) {
69                    out.insert(key, normalize_json(item));
70                }
71            }
72            Value::Object(out)
73        }
74        Value::Array(items) => Value::Array(items.iter().map(normalize_json).collect()),
75        _ => value.clone(),
76    }
77}