Skip to main content

ordinary_utils/
json.rs

1// Copyright (C) 2026 Ordinary Labs, LLC.
2//
3// SPDX-License-Identifier: AGPL-3.0-only
4
5use ref_cast::RefCast;
6use serde_json::{Map, Value as Json};
7#[cfg(tracing_unstable)]
8use valuable::{Listable, Mappable, Valuable, Value, Visit};
9
10#[derive(RefCast)]
11#[repr(transparent)]
12pub struct JsonValuable(pub Json);
13
14#[cfg(tracing_unstable)]
15impl JsonValuable {
16    fn new(json: &Json) -> &JsonValuable {
17        JsonValuable::ref_cast(json)
18    }
19}
20
21#[cfg(tracing_unstable)]
22impl Valuable for JsonValuable {
23    fn as_value(&self) -> Value<'_> {
24        match self.0 {
25            Json::Array(ref array) => JsonValuableArray::new(array).as_value(),
26            Json::Bool(ref value) => value.as_value(),
27            Json::Number(ref num) => {
28                if num.is_f64()
29                    && let Some(num) = num.as_f64()
30                {
31                    Value::F64(num)
32                } else if num.is_i64()
33                    && let Some(num) = num.as_i64()
34                {
35                    Value::I64(num)
36                } else {
37                    unreachable!()
38                }
39            }
40            Json::Null => Value::Unit,
41            Json::String(ref s) => s.as_value(),
42            Json::Object(ref object) => JsonValuableMap::new(object).as_value(),
43        }
44    }
45
46    fn visit(&self, visit: &mut dyn Visit) {
47        match self.0 {
48            Json::Array(ref array) => JsonValuableArray::new(array).visit(visit),
49            Json::Bool(ref value) => value.visit(visit),
50            Json::Number(ref num) => {
51                if num.is_f64()
52                    && let Some(num) = num.as_f64()
53                {
54                    num.visit(visit);
55                } else if num.is_i64()
56                    && let Some(num) = num.as_i64()
57                {
58                    num.visit(visit);
59                } else {
60                    unreachable!()
61                }
62            }
63            Json::Null => Value::Unit.visit(visit),
64            Json::String(ref s) => s.visit(visit),
65            Json::Object(ref object) => JsonValuableMap::new(object).visit(visit),
66        }
67    }
68}
69
70#[derive(RefCast)]
71#[repr(transparent)]
72pub struct JsonValuableMap(pub Map<String, Json>);
73
74#[cfg(tracing_unstable)]
75impl JsonValuableMap {
76    fn new(map: &Map<String, Json>) -> &JsonValuableMap {
77        JsonValuableMap::ref_cast(map)
78    }
79}
80
81#[cfg(tracing_unstable)]
82impl Valuable for JsonValuableMap {
83    fn as_value(&self) -> Value<'_> {
84        Value::Mappable(self)
85    }
86
87    fn visit(&self, visit: &mut dyn Visit) {
88        for (k, v) in &self.0 {
89            visit.visit_entry(k.as_value(), JsonValuable::new(v).as_value());
90        }
91    }
92}
93
94#[cfg(tracing_unstable)]
95impl Mappable for JsonValuableMap {
96    fn size_hint(&self) -> (usize, Option<usize>) {
97        let len = self.0.len();
98        (len, Some(len))
99    }
100}
101
102#[derive(RefCast)]
103#[repr(transparent)]
104pub struct JsonValuableArray(pub Vec<Json>);
105
106#[cfg(tracing_unstable)]
107impl JsonValuableArray {
108    fn new(arr: &Vec<Json>) -> &JsonValuableArray {
109        JsonValuableArray::ref_cast(arr)
110    }
111}
112
113#[cfg(tracing_unstable)]
114impl Valuable for JsonValuableArray {
115    fn as_value(&self) -> Value<'_> {
116        Value::Listable(self)
117    }
118
119    fn visit(&self, visit: &mut dyn Visit) {
120        for v in &self.0 {
121            visit.visit_value(JsonValuable::new(v).as_value());
122        }
123    }
124}
125
126#[cfg(tracing_unstable)]
127impl Listable for JsonValuableArray {
128    fn size_hint(&self) -> (usize, Option<usize>) {
129        let len = self.0.len();
130        (len, Some(len))
131    }
132}