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