1use core::fmt;
2use std::{borrow::Borrow, ops::Deref};
3
4use locspan::Span;
5
6use crate::{
7 JsonValue,
8 print::{
9 Indent, JsonPrintOptions,
10 sizes::{JsonSize, JsonSizesVisitor, printed_string_size},
11 },
12 visitor::JsonVisit,
13};
14
15pub type JsonCodeMapOffset = usize;
16
17#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
19pub struct JsonCodeMap(Vec<JsonCodeMapEntry>);
20
21impl JsonCodeMap {
22 pub fn from_value(value: &JsonValue, options: &JsonPrintOptions) -> Self {
27 let mut sizes = Vec::new();
29 value.visit(JsonSizesVisitor::new(options, &mut sizes));
30
31 let mut result = Self::default();
34 let mut pos = 0usize;
35 let mut sizes_offset = 0usize;
36 result.extent_from_value(value, options, &sizes, &mut sizes_offset, &mut pos, 0);
37 result
38 }
39
40 fn extent_from_value(
41 &mut self,
42 value: &JsonValue,
43 options: &JsonPrintOptions,
44 sizes: &[JsonSize],
45 sizes_offset: &mut usize,
46 pos: &mut usize,
47 indent: usize,
48 ) -> usize {
49 let start = *pos;
50 let my_index = self.len();
51 self.0.push(JsonCodeMapEntry::default()); let volume = match value {
54 JsonValue::Null => {
55 *pos += 4; 1
57 }
58 JsonValue::Boolean(b) => {
59 *pos += if *b { 4 } else { 5 }; 1
61 }
62 JsonValue::Number(n) => {
63 *pos += n.as_str().len();
64 1
65 }
66 JsonValue::String(s) => {
67 *pos += printed_string_size(s);
68 1
69 }
70 JsonValue::Array(items) => {
71 let size = sizes[*sizes_offset];
72 *sizes_offset += 1;
73 *pos += 1; let mut volume = 1;
75
76 match size {
77 JsonSize::Expanded => {
78 *pos += 1; let mut first = true;
80 for item in items.iter() {
81 if first {
82 first = false;
83 } else {
84 *pos += options.array_before_comma; *pos += 2; }
87 *pos += indent_bytes(options.indent, indent + 1);
88 volume += self.extent_from_value(
89 item,
90 options,
91 sizes,
92 sizes_offset,
93 pos,
94 indent + 1,
95 );
96 }
97 if !first {
98 *pos += 1; }
100 *pos += indent_bytes(options.indent, indent); }
102 JsonSize::Width(_) => {
103 let mut first = true;
104 for item in items.iter() {
105 if first {
106 first = false;
107 *pos += options.array_begin;
108 } else {
109 *pos += options.array_before_comma;
110 *pos += 1; *pos += options.array_after_comma;
112 }
113 volume += self.extent_from_value(
114 item,
115 options,
116 sizes,
117 sizes_offset,
118 pos,
119 indent + 1,
120 );
121 }
122 *pos += if first {
123 options.array_empty
124 } else {
125 options.array_end
126 };
127 }
128 }
129
130 *pos += 1; volume
132 }
133 JsonValue::Object(obj) => {
134 let size = sizes[*sizes_offset];
135 *sizes_offset += 1;
136 *pos += 1; let mut volume = 1;
138
139 match size {
140 JsonSize::Expanded => {
141 *pos += 1; let mut first = true;
143 for (key, value) in obj.iter() {
144 if first {
145 first = false;
146 } else {
147 *pos += options.object_before_comma;
148 *pos += 2; }
150 *pos += indent_bytes(options.indent, indent + 1);
151 volume += self.extend_from_entry(
152 options,
153 sizes,
154 sizes_offset,
155 pos,
156 indent,
157 key.as_str(),
158 value,
159 );
160 }
161 if !first {
162 *pos += 1; }
164 *pos += indent_bytes(options.indent, indent); }
166 JsonSize::Width(_) => {
167 let mut first = true;
168 for (key, value) in obj.iter() {
169 if first {
170 first = false;
171 *pos += options.object_begin;
172 } else {
173 *pos += options.object_before_comma;
174 *pos += 1; *pos += options.object_after_comma;
176 }
177 volume += self.extend_from_entry(
178 options,
179 sizes,
180 sizes_offset,
181 pos,
182 indent,
183 key.as_str(),
184 value,
185 );
186 }
187 *pos += if first {
188 options.object_empty
189 } else {
190 options.object_end
191 };
192 }
193 }
194
195 *pos += 1; volume
197 }
198 };
199
200 self.0[my_index] = JsonCodeMapEntry::new(Span::new(start, *pos), volume);
201 volume
202 }
203
204 #[allow(clippy::too_many_arguments)]
205 fn extend_from_entry(
206 &mut self,
207 options: &JsonPrintOptions,
208 sizes: &[JsonSize],
209 sizes_offset: &mut usize,
210 pos: &mut usize,
211 indent: usize,
212 key: &str,
213 value: &JsonValue,
214 ) -> usize {
215 let entry_start = *pos;
216 let entry_index = self.len();
217 self.0.push(JsonCodeMapEntry::default());
218
219 let key_start = *pos;
221 let key_index = self.len();
222 self.0.push(JsonCodeMapEntry::default());
223 *pos += printed_string_size(key);
224 self.0[key_index] = JsonCodeMapEntry::new(Span::new(key_start, *pos), 1);
225
226 *pos += options.object_before_colon;
227 *pos += 1; *pos += options.object_after_colon;
229
230 let value_volume =
231 self.extent_from_value(value, options, sizes, sizes_offset, pos, indent + 1);
232
233 let entry_volume = 1 + 1 + value_volume; self.0[entry_index] = JsonCodeMapEntry::new(Span::new(entry_start, *pos), entry_volume);
235 entry_volume
236 }
237
238 pub fn as_slice(&self) -> &[JsonCodeMapEntry] {
239 &self.0
240 }
241
242 pub(crate) fn reserve(&mut self, position: JsonCodeMapOffset) -> usize {
243 let i = self.0.len();
244
245 self.0.push(JsonCodeMapEntry {
246 span: Span::new(position, position),
247 volume: 0,
248 });
249
250 i
251 }
252
253 pub(crate) fn get_mut(&mut self, offset: JsonCodeMapOffset) -> Option<&mut JsonCodeMapEntry> {
254 self.0.get_mut(offset)
255 }
256
257 pub fn iter(&self) -> Iter<'_> {
258 self.0.iter().enumerate()
259 }
260}
261
262impl Deref for JsonCodeMap {
263 type Target = [JsonCodeMapEntry];
264
265 fn deref(&self) -> &Self::Target {
266 self.as_slice()
267 }
268}
269
270impl AsRef<[JsonCodeMapEntry]> for JsonCodeMap {
271 fn as_ref(&self) -> &[JsonCodeMapEntry] {
272 self.as_slice()
273 }
274}
275
276impl Borrow<[JsonCodeMapEntry]> for JsonCodeMap {
277 fn borrow(&self) -> &[JsonCodeMapEntry] {
278 self.as_slice()
279 }
280}
281
282pub type Iter<'a> = std::iter::Enumerate<std::slice::Iter<'a, JsonCodeMapEntry>>;
283
284pub type IntoIter = std::iter::Enumerate<std::vec::IntoIter<JsonCodeMapEntry>>;
285
286impl<'a> IntoIterator for &'a JsonCodeMap {
287 type IntoIter = Iter<'a>;
288 type Item = (JsonCodeMapOffset, &'a JsonCodeMapEntry);
289
290 fn into_iter(self) -> Self::IntoIter {
291 self.iter()
292 }
293}
294
295impl IntoIterator for JsonCodeMap {
296 type IntoIter = IntoIter;
297 type Item = (JsonCodeMapOffset, JsonCodeMapEntry);
298
299 fn into_iter(self) -> Self::IntoIter {
300 self.0.into_iter().enumerate()
301 }
302}
303
304#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
308pub struct JsonCodeMapEntry {
309 pub span: Span,
311
312 pub volume: usize,
314}
315
316impl JsonCodeMapEntry {
317 pub fn new(span: Span, volume: usize) -> Self {
318 Self { span, volume }
319 }
320}
321
322#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
323pub struct JsonMapped<T>(pub T, pub JsonCodeMapOffset);
324
325impl<T> JsonMapped<T> {
326 pub fn offset(&self) -> JsonCodeMapOffset {
327 self.1
328 }
329
330 pub fn into_offset(self) -> JsonCodeMapOffset {
331 self.1
332 }
333
334 pub fn inner(&self) -> &T {
335 &self.0
336 }
337
338 pub fn into_inner(self) -> T {
339 self.0
340 }
341}
342
343impl<T: fmt::Display> fmt::Display for JsonMapped<T> {
344 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
345 self.0.fmt(f)
346 }
347}
348
349impl<T: 'static + std::error::Error> std::error::Error for JsonMapped<T> {
350 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
351 Some(&self.0)
352 }
353}
354
355fn indent_bytes(indent: Indent, level: usize) -> usize {
358 match indent {
359 Indent::Spaces(n) => n as usize * level,
360 Indent::Tabs(n) => n as usize * level, }
362}
363
364#[cfg(test)]
365mod tests {
366 use super::{JsonCodeMap, JsonCodeMapEntry};
367 use crate::{JsonParse, JsonPrint, JsonValue, print::JsonPrintOptions};
368 use locspan::Span;
369
370 fn check(value: &JsonValue, options: &JsonPrintOptions) {
373 let printed = value.print_with(options).to_string();
374 let (_, expected) = JsonValue::parse_str(&printed).unwrap();
375 let got = JsonCodeMap::from_value(value, options);
376 assert_eq!(
377 got.as_slice(),
378 expected.as_slice(),
379 "mismatch for printed: {printed:?}"
380 );
381 }
382
383 #[test]
384 fn from_value_compact() {
385 for src in ["null", "true", "false", "42", "-3.14", "\"hello\""] {
387 let (value, _) = JsonValue::parse_str(src).unwrap();
388 check(&value, &JsonPrintOptions::COMPACT);
389 }
390
391 let (value, _) = JsonValue::parse_str(r#"{"a":0,"b":[1,2]}"#).unwrap();
393 check(&value, &JsonPrintOptions::COMPACT);
394 }
395
396 #[test]
397 fn from_value_inline() {
398 let (value, _) = JsonValue::parse_str(r#"{"a":0,"b":[1,2]}"#).unwrap();
399 check(&value, &JsonPrintOptions::INLINE);
400 }
401
402 #[test]
403 fn from_value_pretty() {
404 let (value, _) = JsonValue::parse_str(r#"{"a":0,"b":[1,2,3,4,5,6,7,8,9,10]}"#).unwrap();
405 check(&value, &JsonPrintOptions::PRETTY);
406 }
407
408 #[test]
409 fn code_map_t1() {
410 let (value, code_map) = JsonValue::parse_str(r#"{ "a": 0, "b": [1, 2] }"#).unwrap();
411 let expected = [
412 JsonCodeMapEntry::new(Span::new(0, 23), 9), JsonCodeMapEntry::new(Span::new(2, 8), 3), JsonCodeMapEntry::new(Span::new(2, 5), 1), JsonCodeMapEntry::new(Span::new(7, 8), 1), JsonCodeMapEntry::new(Span::new(10, 21), 5), JsonCodeMapEntry::new(Span::new(10, 13), 1), JsonCodeMapEntry::new(Span::new(15, 21), 3), JsonCodeMapEntry::new(Span::new(16, 17), 1), JsonCodeMapEntry::new(Span::new(19, 20), 1), ];
422
423 assert_eq!(code_map.len(), expected.len());
424 assert_eq!(value.traverse().count(), expected.len());
425 for (i, entry) in code_map {
426 assert_eq!(entry, expected[i])
427 }
428 }
429
430 #[test]
431 fn code_map_t2() {
432 let (value, code_map) =
433 JsonValue::parse_str(r#"{ "a": 0, "b": { "c": 1, "d": [2, 3] }, "e": [4, [5, 6]] }"#)
434 .unwrap();
435 let expected = [
436 JsonCodeMapEntry::new(Span::new(0, 58), 22), JsonCodeMapEntry::new(Span::new(2, 8), 3), JsonCodeMapEntry::new(Span::new(2, 5), 1), JsonCodeMapEntry::new(Span::new(7, 8), 1), JsonCodeMapEntry::new(Span::new(10, 38), 11), JsonCodeMapEntry::new(Span::new(10, 13), 1), JsonCodeMapEntry::new(Span::new(15, 38), 9), JsonCodeMapEntry::new(Span::new(17, 23), 3), JsonCodeMapEntry::new(Span::new(17, 20), 1), JsonCodeMapEntry::new(Span::new(22, 23), 1), JsonCodeMapEntry::new(Span::new(25, 36), 5), JsonCodeMapEntry::new(Span::new(25, 28), 1), JsonCodeMapEntry::new(Span::new(30, 36), 3), JsonCodeMapEntry::new(Span::new(31, 32), 1), JsonCodeMapEntry::new(Span::new(34, 35), 1), JsonCodeMapEntry::new(Span::new(40, 56), 7), JsonCodeMapEntry::new(Span::new(40, 43), 1), JsonCodeMapEntry::new(Span::new(45, 56), 5), JsonCodeMapEntry::new(Span::new(46, 47), 1), JsonCodeMapEntry::new(Span::new(49, 55), 3), JsonCodeMapEntry::new(Span::new(50, 51), 1), JsonCodeMapEntry::new(Span::new(53, 54), 1), ];
459
460 assert_eq!(code_map.len(), expected.len());
461 assert_eq!(value.traverse().count(), expected.len());
462 for (i, entry) in code_map {
463 assert_eq!(entry, expected[i])
464 }
465 }
466}