1use std::fmt;
15
16#[derive(Clone, Copy, Debug, PartialEq)]
24pub struct Number<'a> {
25 pub value: f64,
26 pub lexeme: Option<&'a str>,
27}
28
29impl<'a> Number<'a> {
30 pub fn new(value: f64) -> Self {
31 Number {
32 value,
33 lexeme: None,
34 }
35 }
36
37 pub fn with_lexeme(value: f64, lexeme: &'a str) -> Self {
38 Number {
39 value,
40 lexeme: Some(lexeme),
41 }
42 }
43}
44
45#[derive(Clone, Copy, Debug, PartialEq)]
47pub enum JsonEvent<'a> {
48 ObjectStart,
49 ObjectEnd,
50 ArrayStart,
51 ArrayEnd,
52 Key(&'a str),
54 Null,
55 Bool(bool),
56 Number(Number<'a>),
57 String(&'a str),
58 End,
61}
62
63impl JsonEvent<'_> {
64 pub fn to_owned(&self) -> OwnedJsonEvent {
66 match *self {
67 JsonEvent::ObjectStart => OwnedJsonEvent::ObjectStart,
68 JsonEvent::ObjectEnd => OwnedJsonEvent::ObjectEnd,
69 JsonEvent::ArrayStart => OwnedJsonEvent::ArrayStart,
70 JsonEvent::ArrayEnd => OwnedJsonEvent::ArrayEnd,
71 JsonEvent::Key(k) => OwnedJsonEvent::Key(k.into()),
72 JsonEvent::Null => OwnedJsonEvent::Null,
73 JsonEvent::Bool(b) => OwnedJsonEvent::Bool(b),
74 JsonEvent::Number(n) => OwnedJsonEvent::Number {
75 value: n.value,
76 lexeme: n.lexeme.map(Into::into),
77 },
78 JsonEvent::String(s) => OwnedJsonEvent::String(s.into()),
79 JsonEvent::End => OwnedJsonEvent::End,
80 }
81 }
82
83 pub fn is_start(&self) -> bool {
85 matches!(self, JsonEvent::ObjectStart | JsonEvent::ArrayStart)
86 }
87
88 pub fn is_end(&self) -> bool {
90 matches!(self, JsonEvent::ObjectEnd | JsonEvent::ArrayEnd)
91 }
92
93 pub fn is_scalar(&self) -> bool {
95 matches!(
96 self,
97 JsonEvent::Null | JsonEvent::Bool(_) | JsonEvent::Number(_) | JsonEvent::String(_)
98 )
99 }
100}
101
102#[derive(Clone, Debug, PartialEq)]
104pub enum OwnedJsonEvent {
105 ObjectStart,
106 ObjectEnd,
107 ArrayStart,
108 ArrayEnd,
109 Key(Box<str>),
110 Null,
111 Bool(bool),
112 Number {
113 value: f64,
114 lexeme: Option<Box<str>>,
115 },
116 String(Box<str>),
117 End,
118}
119
120impl OwnedJsonEvent {
121 pub fn as_event(&self) -> JsonEvent<'_> {
123 match self {
124 OwnedJsonEvent::ObjectStart => JsonEvent::ObjectStart,
125 OwnedJsonEvent::ObjectEnd => JsonEvent::ObjectEnd,
126 OwnedJsonEvent::ArrayStart => JsonEvent::ArrayStart,
127 OwnedJsonEvent::ArrayEnd => JsonEvent::ArrayEnd,
128 OwnedJsonEvent::Key(k) => JsonEvent::Key(k),
129 OwnedJsonEvent::Null => JsonEvent::Null,
130 OwnedJsonEvent::Bool(b) => JsonEvent::Bool(*b),
131 OwnedJsonEvent::Number { value, lexeme } => JsonEvent::Number(Number {
132 value: *value,
133 lexeme: lexeme.as_deref(),
134 }),
135 OwnedJsonEvent::String(s) => JsonEvent::String(s),
136 OwnedJsonEvent::End => JsonEvent::End,
137 }
138 }
139}
140
141impl fmt::Display for OwnedJsonEvent {
142 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143 match self {
144 OwnedJsonEvent::ObjectStart => f.write_str("{"),
145 OwnedJsonEvent::ObjectEnd => f.write_str("}"),
146 OwnedJsonEvent::ArrayStart => f.write_str("["),
147 OwnedJsonEvent::ArrayEnd => f.write_str("]"),
148 OwnedJsonEvent::Key(k) => write!(f, "key {k:?}"),
149 OwnedJsonEvent::Null => f.write_str("null"),
150 OwnedJsonEvent::Bool(b) => write!(f, "{b}"),
151 OwnedJsonEvent::Number { value, lexeme } => match lexeme {
152 Some(l) => write!(f, "{l}"),
153 None => write!(f, "{value}"),
154 },
155 OwnedJsonEvent::String(s) => write!(f, "{s:?}"),
156 OwnedJsonEvent::End => f.write_str("end"),
157 }
158 }
159}
160
161#[cfg(test)]
162mod tests {
163 use super::*;
164
165 #[test]
166 fn owned_round_trips_through_borrowed() {
167 let events = [
168 JsonEvent::ObjectStart,
169 JsonEvent::Key("a"),
170 JsonEvent::Number(Number::with_lexeme(1.0, "1.0")),
171 JsonEvent::Key("b"),
172 JsonEvent::String("x"),
173 JsonEvent::ObjectEnd,
174 JsonEvent::End,
175 ];
176 for ev in events {
177 let owned = ev.to_owned();
178 assert_eq!(owned.as_event(), ev);
179 }
180 }
181
182 #[test]
183 fn classification() {
184 assert!(JsonEvent::ArrayStart.is_start());
185 assert!(JsonEvent::ObjectEnd.is_end());
186 assert!(JsonEvent::Null.is_scalar());
187 assert!(!JsonEvent::Key("k").is_scalar());
188 assert!(!JsonEvent::End.is_scalar());
189 }
190}