subgraph/
json.rs

1//! Subgraph JSON values.
2
3use crate::{
4    ffi::{
5        boxed::AscRef,
6        buf::AscTypedArray,
7        str::AscString,
8        sys,
9        value::{AscJsonValue, AscJsonValueData},
10    },
11    num::BigInt,
12};
13use indexmap::IndexMap;
14use std::{
15    borrow::Cow,
16    error::Error,
17    fmt::{self, Debug, Display, Formatter},
18    str::FromStr,
19};
20
21/// A Subgraph JSON value.
22#[derive(Clone, Debug, Default, Eq, PartialEq)]
23pub enum Value {
24    #[default]
25    Null,
26    Bool(bool),
27    Number(Number),
28    String(String),
29    Array(Vec<Value>),
30    Object(IndexMap<String, Value>),
31}
32
33impl Value {
34    /// Creates a new instance from a raw JSON value.
35    fn from_raw(raw: &AscRef<AscJsonValue>) -> Self {
36        match raw.data() {
37            AscJsonValueData::Null(()) => Self::Null,
38            AscJsonValueData::Bool(value) => Self::Bool(value),
39            AscJsonValueData::Number(value) => {
40                Self::Number(Number(Cow::Owned(value.to_string_lossy())))
41            }
42            AscJsonValueData::String(value) => Self::String(value.to_string_lossy()),
43            AscJsonValueData::Array(value) => Self::Array(
44                value
45                    .as_slice()
46                    .iter()
47                    .map(|value| Self::from_raw(value.as_asc_ref()))
48                    .collect(),
49            ),
50            AscJsonValueData::Object(value) => Self::Object(
51                value
52                    .entries()
53                    .iter()
54                    .map(|entry| {
55                        let entry = entry.as_asc_ref();
56                        (
57                            entry.key().to_string_lossy(),
58                            Self::from_raw(entry.value().as_asc_ref()),
59                        )
60                    })
61                    .collect(),
62            ),
63        }
64    }
65
66    /// Parses a new JSON from from some bytes.
67    pub fn from_bytes(bytes: impl AsRef<[u8]>) -> Self {
68        let bytes = bytes.as_ref();
69        let array = AscTypedArray::from_bytes(bytes);
70        let raw = unsafe { &*sys::json__from_bytes(array.as_ptr()) };
71
72        Self::from_raw(raw)
73    }
74
75    /// Parses a new JSON value from bytes, returning and error on failure.
76    pub fn try_from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, ParseError> {
77        let bytes = bytes.as_ref();
78        let array = AscTypedArray::from_bytes(bytes);
79        let result = unsafe { &*sys::json__try_from_bytes(array.as_ptr()) };
80        let raw = result.as_std_result().map_err(|_| ParseError)?.as_asc_ref();
81
82        Ok(Self::from_raw(raw))
83    }
84
85    /// Returns the JSON value as a unit value, or `None` if the value is not
86    /// `null`.
87    pub fn as_null(&self) -> Option<()> {
88        match self {
89            Self::Null => Some(()),
90            _ => None,
91        }
92    }
93
94    /// Returns the JSON value as a boolean value, or `None` if the value is not
95    /// `true` or `false`.
96    pub fn as_bool(&self) -> Option<bool> {
97        match self {
98            Self::Bool(value) => Some(*value),
99            _ => None,
100        }
101    }
102
103    /// Returns the JSON value as a numeric value, or `None` if the value is not
104    /// a number.
105    pub fn as_number(&self) -> Option<&Number> {
106        match self {
107            Self::Number(value) => Some(value),
108            _ => None,
109        }
110    }
111
112    /// Returns the JSON value as a string value, or `None` if the value is not
113    /// a string.
114    pub fn as_string(&self) -> Option<&str> {
115        match self {
116            Self::String(value) => Some(value),
117            _ => None,
118        }
119    }
120
121    /// Returns the JSON value as a slice of values, or `None` if the value is
122    /// not an array.
123    pub fn as_array(&self) -> Option<&[Self]> {
124        match self {
125            Self::Array(value) => Some(value),
126            _ => None,
127        }
128    }
129
130    /// Returns the JSON value as a map of values, or `None` if the value is not
131    /// an object.
132    pub fn as_object(&self) -> Option<&IndexMap<String, Self>> {
133        match self {
134            Self::Object(value) => Some(value),
135            _ => None,
136        }
137    }
138}
139
140impl Display for Value {
141    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
142        match self {
143            Self::Null => f.write_str("null"),
144            Self::Bool(value) => write!(f, "{value}"),
145            Self::Number(value) => write!(f, "{value}"),
146            Self::String(value) => write!(f, "{value:?}"),
147            Self::Array(value) => {
148                f.write_str("[")?;
149                for (i, value) in value.iter().enumerate() {
150                    if i > 0 {
151                        f.write_str(",")?;
152                    }
153                    write!(f, "{value}")?;
154                }
155                f.write_str("]")
156            }
157            Self::Object(value) => {
158                f.write_str("{")?;
159                for (i, (key, value)) in value.iter().enumerate() {
160                    if i > 0 {
161                        f.write_str(",")?;
162                    }
163                    write!(f, "\"{key}\":{value}")?;
164                }
165                f.write_str("}")
166            }
167        }
168    }
169}
170
171/// A arbitrary-precision JSON number.
172#[derive(Clone, Eq, PartialEq)]
173pub struct Number(Cow<'static, str>);
174
175impl Number {
176    /// Converts this number to a [`BigInt`].
177    pub fn to_big_int(&self) -> BigInt {
178        let str = AscString::new(&self.0);
179        let raw = unsafe { &*sys::json__to_big_int(str.as_ptr()) };
180        BigInt::from_raw(raw)
181    }
182
183    /// Converts this number to a 64-bit float.
184    pub fn to_f64(&self) -> f64 {
185        let str = AscString::new(&self.0);
186        unsafe { sys::json__to_f64(str.as_ptr()) }
187    }
188
189    /// Converts this number to a 64-bit signed integer.
190    pub fn to_i64(&self) -> i64 {
191        let str = AscString::new(&self.0);
192        unsafe { sys::json__to_i64(str.as_ptr()) }
193    }
194
195    /// Converts this number to a 64-bit un-signed integer.
196    pub fn to_u64(&self) -> u64 {
197        let str = AscString::new(&self.0);
198        unsafe { sys::json__to_u64(str.as_ptr()) }
199    }
200}
201
202impl Debug for Number {
203    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
204        f.write_str(&self.0)
205    }
206}
207
208impl Default for Number {
209    fn default() -> Self {
210        Self(Cow::Borrowed("0"))
211    }
212}
213
214impl Display for Number {
215    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
216        f.write_str(&self.0)
217    }
218}
219
220impl FromStr for Value {
221    type Err = ParseError;
222
223    fn from_str(s: &str) -> Result<Self, Self::Err> {
224        Self::try_from_bytes(s)
225    }
226}
227
228/// A JSON parse error.
229#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
230pub struct ParseError;
231
232impl Display for ParseError {
233    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
234        f.write_str("JSON parse error")
235    }
236}
237
238impl Error for ParseError {}