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