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