1use super::common::Range;
2use super::common::Ranged;
3use std::borrow::Cow;
4
5#[derive(Debug, PartialEq, Clone)]
7pub enum Value<'a> {
8 StringLit(StringLit<'a>),
9 NumberLit(NumberLit<'a>),
10 BooleanLit(BooleanLit),
11 Object(Object<'a>),
12 Array(Array<'a>),
13 NullKeyword(NullKeyword),
14}
15
16impl<'a> Value<'a> {
17 pub fn as_string_lit(&self) -> Option<&StringLit<'a>> {
18 match self {
19 Value::StringLit(node) => Some(node),
20 _ => None,
21 }
22 }
23
24 pub fn as_number_lit(&self) -> Option<&NumberLit<'a>> {
25 match self {
26 Value::NumberLit(node) => Some(node),
27 _ => None,
28 }
29 }
30
31 pub fn as_boolean_lit(&self) -> Option<&BooleanLit> {
32 match self {
33 Value::BooleanLit(node) => Some(node),
34 _ => None,
35 }
36 }
37
38 pub fn as_object(&self) -> Option<&Object<'a>> {
39 match self {
40 Value::Object(node) => Some(node),
41 _ => None,
42 }
43 }
44
45 pub fn as_array(&self) -> Option<&Array<'a>> {
46 match self {
47 Value::Array(node) => Some(node),
48 _ => None,
49 }
50 }
51
52 pub fn as_null_keyword(&self) -> Option<&NullKeyword> {
53 match self {
54 Value::NullKeyword(node) => Some(node),
55 _ => None,
56 }
57 }
58}
59
60#[cfg(feature = "serde")]
61impl<'a> From<Value<'a>> for serde_json::Value {
62 fn from(value: Value<'a>) -> Self {
63 use std::str::FromStr;
64 match value {
65 Value::Array(arr) => {
66 let vec = arr.elements.into_iter().map(|v| v.into()).collect();
67 serde_json::Value::Array(vec)
68 }
69 Value::BooleanLit(b) => serde_json::Value::Bool(b.value),
70 Value::NullKeyword(_) => serde_json::Value::Null,
71 Value::NumberLit(num) => {
72 let number = serde_json::Number::from_str(num.value).expect("could not parse number");
73 serde_json::Value::Number(number)
74 }
75 Value::Object(obj) => {
76 let mut map = serde_json::map::Map::new();
77 for prop in obj.properties {
78 map.insert(prop.name.into_string(), prop.value.into());
79 }
80 serde_json::Value::Object(map)
81 }
82 Value::StringLit(s) => serde_json::Value::String(s.value.into_owned()),
83 }
84 }
85}
86
87#[derive(Debug, PartialEq, Clone, Copy)]
89pub enum Node<'a, 'b> {
90 StringLit(&'b StringLit<'a>),
91 NumberLit(&'b NumberLit<'a>),
92 BooleanLit(&'b BooleanLit),
93 Object(&'b Object<'a>),
94 ObjectProp(&'b ObjectProp<'a>),
95 Array(&'b Array<'a>),
96 NullKeyword(&'b NullKeyword),
97 WordLit(&'b WordLit<'a>),
98}
99
100impl<'a, 'b> Node<'a, 'b> {
101 pub fn kind(&self) -> NodeKind {
103 match self {
104 Node::StringLit(_) => NodeKind::StringLit,
105 Node::NumberLit(_) => NodeKind::NumberLit,
106 Node::BooleanLit(_) => NodeKind::BooleanLit,
107 Node::Object(_) => NodeKind::Object,
108 Node::ObjectProp(_) => NodeKind::ObjectProp,
109 Node::Array(_) => NodeKind::Array,
110 Node::NullKeyword(_) => NodeKind::NullKeyword,
111 Node::WordLit(_) => NodeKind::WordLit,
112 }
113 }
114
115 pub fn as_string_lit(&self) -> Option<&'b StringLit<'a>> {
116 match self {
117 Node::StringLit(node) => Some(node),
118 _ => None,
119 }
120 }
121
122 pub fn as_number_lit(&self) -> Option<&'b NumberLit<'a>> {
123 match self {
124 Node::NumberLit(node) => Some(node),
125 _ => None,
126 }
127 }
128
129 pub fn as_boolean_lit(&self) -> Option<&'b BooleanLit> {
130 match self {
131 Node::BooleanLit(node) => Some(node),
132 _ => None,
133 }
134 }
135
136 pub fn as_object(&self) -> Option<&'b Object<'a>> {
137 match self {
138 Node::Object(node) => Some(node),
139 _ => None,
140 }
141 }
142
143 pub fn as_object_prop(&self) -> Option<&'b ObjectProp<'a>> {
144 match self {
145 Node::ObjectProp(node) => Some(node),
146 _ => None,
147 }
148 }
149
150 pub fn as_array(&self) -> Option<&'b Array<'a>> {
151 match self {
152 Node::Array(node) => Some(node),
153 _ => None,
154 }
155 }
156
157 pub fn as_null_keyword(&self) -> Option<&'b NullKeyword> {
158 match self {
159 Node::NullKeyword(node) => Some(node),
160 _ => None,
161 }
162 }
163
164 pub fn as_word_lit(&self) -> Option<&'b WordLit<'a>> {
165 match self {
166 Node::WordLit(node) => Some(node),
167 _ => None,
168 }
169 }
170}
171
172#[derive(Debug, PartialEq, Clone, Copy)]
174pub enum NodeKind {
175 StringLit,
176 NumberLit,
177 BooleanLit,
178 Object,
179 ObjectProp,
180 Array,
181 NullKeyword,
182 WordLit,
183}
184
185#[derive(Debug, PartialEq, Clone)]
187pub struct StringLit<'a> {
188 pub range: Range,
189 pub value: Cow<'a, str>,
190}
191
192#[derive(Debug, PartialEq, Clone)]
195pub struct WordLit<'a> {
196 pub range: Range,
197 pub value: &'a str,
198}
199
200#[derive(Debug, PartialEq, Clone)]
202pub struct NumberLit<'a> {
203 pub range: Range,
204 pub value: &'a str,
205}
206
207#[derive(Debug, PartialEq, Clone)]
209pub struct BooleanLit {
210 pub range: Range,
211 pub value: bool,
212}
213
214#[derive(Debug, PartialEq, Clone)]
216pub struct NullKeyword {
217 pub range: Range,
218}
219
220#[derive(Debug, PartialEq, Clone)]
222pub struct Object<'a> {
223 pub range: Range,
224 pub properties: Vec<ObjectProp<'a>>,
225}
226
227macro_rules! generate_take {
228 ($self:ident, $name:ident, $value_type:ident) => {
229 if let Some(pos) = $self.properties.iter().position(|p| p.name.as_str() == $name) {
231 if let Value::$value_type(_) = &$self.properties[pos].value {
232 if let Value::$value_type(node) = $self.properties.remove(pos).value {
233 Some(node)
234 } else {
235 None
236 }
237 } else {
238 None
239 }
240 } else {
241 None
242 }
243 };
244}
245
246macro_rules! generate_get {
247 ($self:ident, $name:ident, $value_type:ident) => {
248 $self
249 .properties
250 .iter()
251 .filter(|p| p.name.as_str() == $name)
252 .map(|p| {
253 if let Value::$value_type(node) = &p.value {
254 Some(node)
255 } else {
256 None
257 }
258 })
259 .next()
260 .flatten()
261 };
262}
263
264impl<'a> Object<'a> {
265 pub fn get(&self, name: &str) -> Option<&ObjectProp<'a>> {
267 self.properties.iter().find(|p| p.name.as_str() == name)
268 }
269
270 pub fn get_string(&self, name: &str) -> Option<&StringLit<'a>> {
273 generate_get!(self, name, StringLit)
274 }
275
276 pub fn get_number(&self, name: &str) -> Option<&NumberLit<'a>> {
279 generate_get!(self, name, NumberLit)
280 }
281
282 pub fn get_boolean(&self, name: &str) -> Option<&BooleanLit> {
285 generate_get!(self, name, BooleanLit)
286 }
287
288 pub fn get_object(&self, name: &str) -> Option<&Object<'a>> {
291 generate_get!(self, name, Object)
292 }
293
294 pub fn get_array(&self, name: &str) -> Option<&Array<'a>> {
297 generate_get!(self, name, Array)
298 }
299
300 pub fn take(&mut self, name: &str) -> Option<ObjectProp<'a>> {
303 if let Some(pos) = self.properties.iter().position(|p| p.name.as_str() == name) {
304 Some(self.properties.remove(pos))
305 } else {
306 None
307 }
308 }
309
310 pub fn take_string(&mut self, name: &str) -> Option<StringLit<'a>> {
313 generate_take!(self, name, StringLit)
314 }
315
316 pub fn take_number(&mut self, name: &str) -> Option<NumberLit<'a>> {
319 generate_take!(self, name, NumberLit)
320 }
321
322 pub fn take_boolean(&mut self, name: &str) -> Option<BooleanLit> {
325 generate_take!(self, name, BooleanLit)
326 }
327
328 pub fn take_object(&mut self, name: &str) -> Option<Object<'a>> {
331 generate_take!(self, name, Object)
332 }
333
334 pub fn take_array(&mut self, name: &str) -> Option<Array<'a>> {
337 generate_take!(self, name, Array)
338 }
339}
340
341#[derive(Debug, PartialEq, Clone)]
343pub struct ObjectProp<'a> {
344 pub range: Range,
345 pub name: ObjectPropName<'a>,
346 pub value: Value<'a>,
347}
348
349#[derive(Debug, PartialEq, Clone)]
351pub enum ObjectPropName<'a> {
352 String(StringLit<'a>),
353 Word(WordLit<'a>),
354}
355
356impl<'a> ObjectPropName<'a> {
357 pub fn into_string(self) -> String {
359 match self {
360 ObjectPropName::String(lit) => lit.value.into_owned(),
361 ObjectPropName::Word(lit) => lit.value.to_string(),
362 }
363 }
364
365 pub fn as_str(&'a self) -> &'a str {
367 match self {
368 ObjectPropName::String(lit) => lit.value.as_ref(),
369 ObjectPropName::Word(lit) => lit.value,
370 }
371 }
372}
373
374#[derive(Debug, PartialEq, Clone)]
376pub struct Array<'a> {
377 pub range: Range,
378 pub elements: Vec<Value<'a>>,
379}
380
381#[derive(Debug, PartialEq, Clone)]
383pub enum CommentKind {
384 Line,
385 Block,
386}
387
388#[derive(Debug, PartialEq, Clone)]
390pub enum Comment<'a> {
391 Line(CommentLine<'a>),
392 Block(CommentBlock<'a>),
393}
394
395impl<'a> Comment<'a> {
396 pub fn text(&self) -> &'a str {
398 match self {
399 Comment::Line(line) => line.text,
400 Comment::Block(line) => line.text,
401 }
402 }
403
404 pub fn kind(&self) -> CommentKind {
406 match self {
407 Comment::Line(_) => CommentKind::Line,
408 Comment::Block(_) => CommentKind::Block,
409 }
410 }
411}
412
413impl<'a> Ranged for Comment<'a> {
414 fn range(&self) -> Range {
415 match self {
416 Comment::Line(line) => line.range(),
417 Comment::Block(line) => line.range(),
418 }
419 }
420}
421
422#[derive(Debug, PartialEq, Clone)]
424pub struct CommentLine<'a> {
425 pub range: Range,
426 pub text: &'a str,
427}
428
429#[derive(Debug, PartialEq, Clone)]
431pub struct CommentBlock<'a> {
432 pub range: Range,
433 pub text: &'a str,
434}
435
436impl<'a, 'b> From<&'b ObjectPropName<'a>> for Node<'a, 'b> {
439 fn from(object_prop_name: &'b ObjectPropName<'a>) -> Node<'a, 'b> {
440 match object_prop_name {
441 ObjectPropName::String(lit) => lit.into(),
442 ObjectPropName::Word(lit) => lit.into(),
443 }
444 }
445}
446
447impl<'a> Ranged for ObjectPropName<'a> {
448 fn range(&self) -> Range {
449 match self {
450 ObjectPropName::String(lit) => lit.range(),
451 ObjectPropName::Word(lit) => lit.range(),
452 }
453 }
454}
455
456macro_rules! impl_ranged {
459 ($($node_name:ident),*) => {
460 $(
461 impl Ranged for $node_name {
462 fn range(&self) -> Range {
463 self.range
464 }
465 }
466 )*
467 };
468}
469
470impl_ranged![BooleanLit, NullKeyword];
471
472macro_rules! impl_ranged_lifetime {
473 ($($node_name:ident),*) => {
474 $(
475 impl<'a> Ranged for $node_name<'a> {
476 fn range(&self) -> Range {
477 self.range
478 }
479 }
480 )*
481 };
482}
483
484impl_ranged_lifetime![
485 WordLit,
486 Object,
487 ObjectProp,
488 Array,
489 CommentLine,
490 CommentBlock,
491 NumberLit,
492 StringLit
493];
494
495impl<'a> Ranged for Value<'a> {
496 fn range(&self) -> Range {
497 match self {
498 Value::Array(node) => node.range(),
499 Value::BooleanLit(node) => node.range(),
500 Value::NullKeyword(node) => node.range(),
501 Value::NumberLit(node) => node.range(),
502 Value::Object(node) => node.range(),
503 Value::StringLit(node) => node.range(),
504 }
505 }
506}
507
508impl<'a, 'b> Ranged for Node<'a, 'b> {
509 fn range(&self) -> Range {
510 match self {
511 Node::StringLit(node) => node.range(),
512 Node::NumberLit(node) => node.range(),
513 Node::BooleanLit(node) => node.range(),
514 Node::NullKeyword(node) => node.range(),
515 Node::WordLit(node) => node.range(),
516 Node::Array(node) => node.range(),
517 Node::Object(node) => node.range(),
518 Node::ObjectProp(node) => node.range(),
519 }
520 }
521}
522
523macro_rules! generate_node {
524 ($($node_name:ident),*) => {
525 $(
526 impl<'a, 'b> From<&'b $node_name> for Node<'a, 'b> {
527 fn from(node: &'b $node_name) -> Node<'a, 'b> {
528 Node::$node_name(node)
529 }
530 }
531 )*
532 };
533}
534
535generate_node![BooleanLit, NullKeyword];
536
537macro_rules! generate_node_lifetime {
538 ($($node_name:ident),*) => {
539
540 $(
541 impl<'a, 'b> From<&'b $node_name<'a>> for Node<'a, 'b> {
542 fn from(node: &'b $node_name<'a>) -> Node<'a, 'b> {
543 Node::$node_name(node)
544 }
545 }
546 )*
547 };
548}
549
550generate_node_lifetime![WordLit, Object, ObjectProp, Array, NumberLit, StringLit];
551
552impl<'a, 'b> From<&'b Value<'a>> for Node<'a, 'b> {
553 fn from(value: &'b Value<'a>) -> Node<'a, 'b> {
554 match value {
555 Value::Array(node) => Node::Array(node),
556 Value::BooleanLit(node) => Node::BooleanLit(node),
557 Value::NullKeyword(node) => Node::NullKeyword(node),
558 Value::NumberLit(node) => Node::NumberLit(node),
559 Value::Object(node) => Node::Object(node),
560 Value::StringLit(node) => Node::StringLit(node),
561 }
562 }
563}
564
565#[cfg(test)]
566mod test {
567 use super::*;
568 use crate::parse_to_ast;
569 use crate::ParseOptions;
570
571 #[test]
572 fn it_should_take() {
573 let ast = parse_to_ast(
574 "{'prop': 'asdf', 'other': 'text'}",
575 &Default::default(),
576 &ParseOptions::default(),
577 )
578 .unwrap();
579 let mut obj = match ast.value {
580 Some(Value::Object(obj)) => obj,
581 _ => unreachable!(),
582 };
583
584 assert_eq!(obj.properties.len(), 2);
585 assert_eq!(obj.take_string("asdf"), None);
586 assert_eq!(obj.properties.len(), 2);
587 assert_eq!(obj.take_number("prop"), None);
588 assert_eq!(obj.properties.len(), 2);
589 assert!(obj.take_string("prop").is_some());
590 assert_eq!(obj.properties.len(), 1);
591 assert_eq!(obj.take("something"), None);
592 assert_eq!(obj.properties.len(), 1);
593 assert!(obj.take("other").is_some());
594 assert_eq!(obj.properties.len(), 0);
595 }
596
597 #[test]
598 fn it_should_get() {
599 let ast = parse_to_ast("{'prop': 'asdf'}", &Default::default(), &ParseOptions::default()).unwrap();
600 let obj = match ast.value {
601 Some(Value::Object(obj)) => obj,
602 _ => unreachable!(),
603 };
604
605 assert_eq!(obj.properties.len(), 1);
606 assert_eq!(obj.get_string("asdf"), None);
607 assert!(obj.get_string("prop").is_some());
608 assert_eq!(obj.get("asdf"), None);
609 assert_eq!(obj.properties.len(), 1);
610 }
611
612 #[cfg(feature = "serde")]
613 #[test]
614 fn it_should_coerce_to_serde_value() {
615 let ast = parse_to_ast(
616 r#"{"prop":[true,1,null,"str"]}"#,
617 &Default::default(),
618 &ParseOptions::default(),
619 )
620 .unwrap();
621 let value = ast.value.unwrap();
622 let serde_value: serde_json::Value = value.into();
623
624 assert_eq!(
625 serde_value,
626 serde_json::json!({
627 "prop": [
628 true,
629 1,
630 null,
631 "str"
632 ]
633 })
634 );
635 }
636}