Skip to main content

oak_json/ast/
mod.rs

1#![doc = include_str!("readme.md")]
2use core::range::Range;
3use oak_core::source::{SourceBuffer, ToSource};
4#[cfg(feature = "serde")]
5use serde::{Deserialize, Serialize};
6
7#[cfg(feature = "oak-pretty-print")]
8use oak_pretty_print::{AsDocument, doc as pp_doc};
9
10/// The root node of a JSON AST.
11#[derive(Clone, Debug, PartialEq)]
12#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
13#[cfg_attr(feature = "oak-pretty-print", derive(AsDocument))]
14pub struct JsonRoot {
15    /// The top-level value of the JSON document.
16    pub value: JsonValue,
17}
18
19impl ToSource for JsonRoot {
20    fn to_source(&self, buffer: &mut SourceBuffer) {
21        self.value.to_source(buffer)
22    }
23}
24
25/// Represents any valid JSON value.
26#[derive(Clone, Debug, PartialEq)]
27#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
28#[cfg_attr(feature = "oak-pretty-print", derive(AsDocument))]
29pub enum JsonValue {
30    /// A JSON object (collection of key-value pairs).
31    Object(JsonObject),
32    /// A JSON array (ordered list of values).
33    Array(JsonArray),
34    /// A JSON string.
35    String(JsonString),
36    /// A JSON number (represented as f64).
37    Number(JsonNumber),
38    /// A JSON boolean (true or false).
39    Boolean(JsonBoolean),
40    /// A JSON null value.
41    Null(JsonNull),
42}
43
44impl JsonValue {
45    pub fn as_str(&self) -> Option<&str> {
46        match self {
47            JsonValue::String(s) => Some(&s.value),
48            _ => None,
49        }
50    }
51
52    pub fn as_f64(&self) -> Option<f64> {
53        match self {
54            JsonValue::Number(n) => Some(n.value),
55            _ => None,
56        }
57    }
58
59    pub fn as_bool(&self) -> Option<bool> {
60        match self {
61            JsonValue::Boolean(b) => Some(b.value),
62            _ => None,
63        }
64    }
65
66    pub fn as_u64(&self) -> Option<u64> {
67        self.as_f64().map(|f| f as u64)
68    }
69
70    pub fn as_array(&self) -> Option<&JsonArray> {
71        match self {
72            JsonValue::Array(a) => Some(a),
73            _ => None,
74        }
75    }
76
77    pub fn as_object(&self) -> Option<&JsonObject> {
78        match self {
79            JsonValue::Object(o) => Some(o),
80            _ => None,
81        }
82    }
83
84    pub fn get(&self, key: &str) -> Option<&JsonValue> {
85        match self {
86            JsonValue::Object(o) => o.get(key),
87            _ => None,
88        }
89    }
90
91    pub fn to_string(&self) -> String {
92        match self {
93            JsonValue::Null(_) => "null".to_string(),
94            JsonValue::Boolean(b) => b.value.to_string(),
95            JsonValue::Number(n) => n.value.to_string(),
96            JsonValue::String(s) => format!("\"{}\"", s.value),
97            JsonValue::Array(a) => {
98                let elements: Vec<String> = a.elements.iter().map(|e| e.to_string()).collect();
99                format!("[{}]", elements.join(","))
100            }
101            JsonValue::Object(o) => {
102                let fields: Vec<String> = o.fields.iter().map(|f| format!("\"{}\":{}", f.name.value, f.value.to_string())).collect();
103                format!("{{{}}}", fields.join(","))
104            }
105        }
106    }
107}
108
109impl std::fmt::Display for JsonValue {
110    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111        write!(f, "{}", self.to_string())
112    }
113}
114
115impl From<&str> for JsonValue {
116    fn from(s: &str) -> Self {
117        JsonValue::String(JsonString { value: s.to_string(), span: (0..0).into() })
118    }
119}
120
121impl From<String> for JsonValue {
122    fn from(s: String) -> Self {
123        JsonValue::String(JsonString { value: s, span: (0..0).into() })
124    }
125}
126
127impl From<f64> for JsonValue {
128    fn from(f: f64) -> Self {
129        JsonValue::Number(JsonNumber { value: f, span: (0..0).into() })
130    }
131}
132
133impl From<u64> for JsonValue {
134    fn from(u: u64) -> Self {
135        JsonValue::Number(JsonNumber { value: u as f64, span: (0..0).into() })
136    }
137}
138
139impl From<i32> for JsonValue {
140    fn from(i: i32) -> Self {
141        JsonValue::Number(JsonNumber { value: i as f64, span: (0..0).into() })
142    }
143}
144
145impl From<i64> for JsonValue {
146    fn from(i: i64) -> Self {
147        JsonValue::Number(JsonNumber { value: i as f64, span: (0..0).into() })
148    }
149}
150
151impl From<usize> for JsonValue {
152    fn from(u: usize) -> Self {
153        JsonValue::Number(JsonNumber { value: u as f64, span: (0..0).into() })
154    }
155}
156
157impl From<bool> for JsonValue {
158    fn from(b: bool) -> Self {
159        JsonValue::Boolean(JsonBoolean { value: b, span: (0..0).into() })
160    }
161}
162
163impl From<u32> for JsonValue {
164    fn from(value: u32) -> Self {
165        JsonValue::Number(JsonNumber { value: value as f64, span: (0..0).into() })
166    }
167}
168
169impl From<f32> for JsonValue {
170    fn from(value: f32) -> Self {
171        JsonValue::Number(JsonNumber { value: value as f64, span: (0..0).into() })
172    }
173}
174
175impl<T: Into<JsonValue>> From<Option<T>> for JsonValue {
176    fn from(value: Option<T>) -> Self {
177        match value {
178            Some(v) => v.into(),
179            None => JsonValue::Null(JsonNull { span: (0..0).into() }),
180        }
181    }
182}
183
184impl From<()> for JsonValue {
185    fn from(_: ()) -> Self {
186        JsonValue::Null(JsonNull { span: (0..0).into() })
187    }
188}
189
190impl From<[JsonValue; 0]> for JsonValue {
191    fn from(_: [JsonValue; 0]) -> Self {
192        JsonValue::Array(JsonArray { elements: vec![], span: (0..0).into() })
193    }
194}
195
196impl From<Vec<JsonValue>> for JsonValue {
197    fn from(elements: Vec<JsonValue>) -> Self {
198        JsonValue::Array(JsonArray { elements, span: (0..0).into() })
199    }
200}
201
202impl From<std::collections::HashMap<String, JsonValue>> for JsonValue {
203    fn from(fields: std::collections::HashMap<String, JsonValue>) -> Self {
204        let mut fields_vec: Vec<JsonField> = fields.into_iter().map(|(k, v)| JsonField { name: JsonString { value: k, span: (0..0).into() }, value: v, span: (0..0).into() }).collect();
205        // Sort fields by name for consistent output
206        fields_vec.sort_by(|a, b| a.name.value.cmp(&b.name.value));
207        JsonValue::Object(JsonObject { fields: fields_vec, span: (0..0).into() })
208    }
209}
210
211impl<T: Into<JsonValue>> FromIterator<T> for JsonValue {
212    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
213        JsonValue::Array(JsonArray { elements: iter.into_iter().map(Into::into).collect(), span: (0..0).into() })
214    }
215}
216
217impl ToSource for JsonValue {
218    fn to_source(&self, buffer: &mut SourceBuffer) {
219        match self {
220            JsonValue::Object(v) => v.to_source(buffer),
221            JsonValue::Array(v) => v.to_source(buffer),
222            JsonValue::String(v) => v.to_source(buffer),
223            JsonValue::Number(v) => v.to_source(buffer),
224            JsonValue::Boolean(v) => v.to_source(buffer),
225            JsonValue::Null(v) => v.to_source(buffer),
226        }
227    }
228}
229
230/// Represents a JSON object.
231#[derive(Clone, Debug, PartialEq)]
232#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
233#[cfg_attr(feature = "oak-pretty-print", derive(AsDocument))]
234#[cfg_attr(feature = "oak-pretty-print", oak(doc = 
235    if _self.fields.is_empty() {
236        pp_doc!("{}")
237    } else {
238        pp_doc!(group( [
239            "{",
240            indent( [line, join(_self.fields.iter(), [",", line])]),
241            line,
242            "}"
243        ]))
244    }
245))]
246pub struct JsonObject {
247    /// The fields (key-value pairs) of the object.
248    pub fields: Vec<JsonField>,
249    /// The source range of the object.
250    #[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
251    pub span: Range<usize>,
252}
253
254impl JsonObject {
255    /// Returns the value associated with the given key, if it exists.
256    pub fn get(&self, key: &str) -> Option<&JsonValue> {
257        self.fields.iter().find(|f| f.name.value == key).map(|f| &f.value)
258    }
259}
260
261impl ToSource for JsonObject {
262    fn to_source(&self, buffer: &mut SourceBuffer) {
263        buffer.push("{");
264        for (i, field) in self.fields.iter().enumerate() {
265            if i > 0 {
266                buffer.push(",")
267            }
268            field.to_source(buffer)
269        }
270        buffer.push("}")
271    }
272}
273
274/// Represents a single field (key-value pair) in a JSON object.
275#[derive(Clone, Debug, PartialEq)]
276#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
277#[cfg_attr(feature = "oak-pretty-print", derive(AsDocument))]
278#[cfg_attr(feature = "oak-pretty-print", oak(doc = [self.name.as_document(), ": ", self.value.as_document()]))]
279pub struct JsonField {
280    /// The name (key) of the field.
281    pub name: JsonString,
282    /// The value of the field.
283    pub value: JsonValue,
284    /// The source range of the field.
285    #[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
286    pub span: Range<usize>,
287}
288
289impl ToSource for JsonField {
290    fn to_source(&self, buffer: &mut SourceBuffer) {
291        self.name.to_source(buffer);
292        buffer.push(":");
293        self.value.to_source(buffer)
294    }
295}
296
297/// Represents a JSON array.
298#[derive(Clone, Debug, PartialEq)]
299#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
300#[cfg_attr(feature = "oak-pretty-print", derive(AsDocument))]
301#[cfg_attr(feature = "oak-pretty-print", oak(doc = 
302    if _self.elements.is_empty() {
303        pp_doc!("[]")
304    } else {
305        pp_doc!(group( [
306            "[",
307            indent( [line, join(_self.elements.iter(), [",", line])]),
308            line,
309            "]"
310        ]))
311    }
312))]
313pub struct JsonArray {
314    /// The elements of the array.
315    pub elements: Vec<JsonValue>,
316    /// The source range of the array.
317    #[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
318    pub span: Range<usize>,
319}
320
321impl ToSource for JsonArray {
322    fn to_source(&self, buffer: &mut SourceBuffer) {
323        buffer.push("[");
324        for (i, element) in self.elements.iter().enumerate() {
325            if i > 0 {
326                buffer.push(",")
327            }
328            element.to_source(buffer)
329        }
330        buffer.push("]")
331    }
332}
333
334/// Represents a JSON string literal.
335#[derive(Clone, Debug, PartialEq)]
336#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
337#[cfg_attr(feature = "oak-pretty-print", derive(AsDocument))]
338#[cfg_attr(feature = "oak-pretty-print", oak(doc = format!("\"{}\"", self.value)))]
339pub struct JsonString {
340    /// The string content (without quotes).
341    pub value: String,
342    /// The source range of the string literal.
343    #[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
344    pub span: Range<usize>,
345}
346
347impl ToSource for JsonString {
348    fn to_source(&self, buffer: &mut SourceBuffer) {
349        buffer.push("\"");
350        buffer.push(&self.value);
351        buffer.push("\"")
352    }
353}
354
355/// Represents a JSON number literal.
356#[derive(Clone, Debug, PartialEq)]
357#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
358#[cfg_attr(feature = "oak-pretty-print", derive(AsDocument))]
359#[cfg_attr(feature = "oak-pretty-print", oak(doc = self.value.to_string()))]
360pub struct JsonNumber {
361    /// The numeric value.
362    pub value: f64,
363    /// The source range of the number literal.
364    #[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
365    pub span: Range<usize>,
366}
367
368impl ToSource for JsonNumber {
369    fn to_source(&self, buffer: &mut SourceBuffer) {
370        buffer.push(&self.value.to_string())
371    }
372}
373
374/// Represents a JSON boolean literal.
375#[derive(Clone, Debug, PartialEq)]
376#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
377#[cfg_attr(feature = "oak-pretty-print", derive(AsDocument))]
378#[cfg_attr(feature = "oak-pretty-print", oak(doc = if self.value { "true" } else { "false" }))]
379pub struct JsonBoolean {
380    /// The boolean value.
381    pub value: bool,
382    /// The source range of the boolean literal.
383    #[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
384    pub span: Range<usize>,
385}
386
387impl ToSource for JsonBoolean {
388    fn to_source(&self, buffer: &mut SourceBuffer) {
389        buffer.push(if self.value { "true" } else { "false" })
390    }
391}
392
393/// Represents a JSON null literal.
394#[derive(Clone, Debug, PartialEq)]
395#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
396#[cfg_attr(feature = "oak-pretty-print", derive(AsDocument))]
397#[cfg_attr(feature = "oak-pretty-print", oak(doc = "null"))]
398pub struct JsonNull {
399    /// The source range of the null literal.
400    #[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
401    pub span: Range<usize>,
402}
403
404impl ToSource for JsonNull {
405    fn to_source(&self, buffer: &mut SourceBuffer) {
406        buffer.push("null")
407    }
408}