1use std::fmt;
2
3#[cfg(feature = "contextual")]
4mod contextual;
5
6#[cfg(feature = "contextual")]
7pub use self::contextual::*;
8
9#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
10pub enum Indent {
11 Spaces(u8),
12 Tabs(u8),
13}
14
15impl Indent {
16 pub fn by(self, n: usize) -> IndentBy {
17 IndentBy(self, n)
18 }
19}
20
21impl fmt::Display for Indent {
22 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
23 match self {
24 Self::Spaces(n) => {
25 for _ in 0..*n {
26 f.write_str(" ")?
27 }
28 }
29 Self::Tabs(n) => {
30 for _ in 0..*n {
31 f.write_str("\t")?
32 }
33 }
34 }
35
36 Ok(())
37 }
38}
39
40pub struct IndentBy(Indent, usize);
41
42impl fmt::Display for IndentBy {
43 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
44 for _ in 0..self.1 {
45 self.0.fmt(f)?
46 }
47
48 Ok(())
49 }
50}
51
52pub struct Spaces(pub usize);
53
54impl fmt::Display for Spaces {
55 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
56 for _ in 0..self.0 {
57 f.write_str(" ")?
58 }
59
60 Ok(())
61 }
62}
63
64#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
65pub enum Padding {
66 Spaces(u8),
67 NewLine,
68}
69
70impl fmt::Display for Padding {
71 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72 match self {
73 Self::Spaces(n) => {
74 for _ in 0..*n {
75 f.write_str(" ")?
76 }
77 }
78 Self::NewLine => f.write_str("\n")?,
79 }
80
81 Ok(())
82 }
83}
84
85#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
86pub enum Limit {
87 Always,
89
90 Item(usize),
92
93 Width(usize),
96
97 ItemOrWidth(usize, usize),
101}
102
103#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
105#[non_exhaustive]
106pub struct Options {
107 pub indent: Indent,
109
110 pub array_begin: usize,
112
113 pub array_end: usize,
115
116 pub array_empty: usize,
118
119 pub array_before_comma: usize,
121
122 pub array_after_comma: usize,
124
125 pub array_limit: Option<Limit>,
127
128 pub object_begin: usize,
130
131 pub object_end: usize,
133
134 pub object_empty: usize,
136
137 pub object_before_comma: usize,
139
140 pub object_after_comma: usize,
142
143 pub object_before_colon: usize,
145
146 pub object_after_colon: usize,
148
149 pub object_limit: Option<Limit>,
151}
152
153impl Options {
154 #[inline(always)]
156 pub fn pretty() -> Self {
157 Self {
158 indent: Indent::Spaces(2),
159 array_begin: 1,
160 array_end: 1,
161 array_empty: 0,
162 array_before_comma: 0,
163 array_after_comma: 1,
164 array_limit: Some(Limit::ItemOrWidth(1, 16)),
165 object_begin: 1,
166 object_end: 1,
167 object_empty: 0,
168 object_before_comma: 0,
169 object_after_comma: 1,
170 object_before_colon: 0,
171 object_after_colon: 1,
172 object_limit: Some(Limit::ItemOrWidth(1, 16)),
173 }
174 }
175
176 #[inline(always)]
180 pub fn compact() -> Self {
181 Self {
182 indent: Indent::Spaces(0),
183 array_begin: 0,
184 array_end: 0,
185 array_empty: 0,
186 array_before_comma: 0,
187 array_after_comma: 0,
188 array_limit: None,
189 object_begin: 0,
190 object_end: 0,
191 object_empty: 0,
192 object_before_comma: 0,
193 object_after_comma: 0,
194 object_before_colon: 0,
195 object_after_colon: 0,
196 object_limit: None,
197 }
198 }
199
200 #[inline(always)]
204 pub fn inline() -> Self {
205 Self {
206 indent: Indent::Spaces(0),
207 array_begin: 1,
208 array_end: 1,
209 array_empty: 0,
210 array_before_comma: 0,
211 array_after_comma: 1,
212 array_limit: None,
213 object_begin: 1,
214 object_end: 1,
215 object_empty: 0,
216 object_before_comma: 0,
217 object_after_comma: 1,
218 object_before_colon: 0,
219 object_after_colon: 1,
220 object_limit: None,
221 }
222 }
223}
224
225#[derive(Clone, Copy)]
227pub enum Size {
228 Expanded,
230
231 Width(usize),
233}
234
235impl Size {
236 pub fn add(&mut self, other: Self) {
237 *self = match (*self, other) {
238 (Self::Width(a), Self::Width(b)) => Self::Width(a + b),
239 _ => Self::Expanded,
240 }
241 }
242}
243
244pub trait Print {
246 #[inline(always)]
248 fn pretty_print(&self) -> Printed<'_, Self> {
249 self.print_with(Options::pretty())
250 }
251
252 #[inline(always)]
254 fn compact_print(&self) -> Printed<'_, Self> {
255 self.print_with(Options::compact())
256 }
257
258 #[inline(always)]
260 fn inline_print(&self) -> Printed<'_, Self> {
261 self.print_with(Options::inline())
262 }
263
264 #[inline(always)]
266 fn print_with(&self, options: Options) -> Printed<'_, Self> {
267 Printed(self, options, 0)
268 }
269
270 fn fmt_with(&self, f: &mut fmt::Formatter, options: &Options, indent: usize) -> fmt::Result;
271}
272
273impl<T: Print> Print for locspan::Stripped<T> {
274 fn fmt_with(&self, f: &mut fmt::Formatter, options: &Options, indent: usize) -> fmt::Result {
275 self.0.fmt_with(f, options, indent)
276 }
277}
278
279impl<T: Print, M> Print for locspan::Meta<T, M> {
280 fn fmt_with(&self, f: &mut fmt::Formatter, options: &Options, indent: usize) -> fmt::Result {
281 self.value().fmt_with(f, options, indent)
282 }
283}
284
285impl<'a, T: Print + ?Sized> Print for &'a T {
286 fn fmt_with(&self, f: &mut fmt::Formatter, options: &Options, indent: usize) -> fmt::Result {
287 (**self).fmt_with(f, options, indent)
288 }
289}
290
291pub trait PrintWithSize {
292 fn fmt_with_size(
293 &self,
294 f: &mut fmt::Formatter,
295 options: &Options,
296 indent: usize,
297 sizes: &[Size],
298 index: &mut usize,
299 ) -> fmt::Result;
300}
301
302impl<T: PrintWithSize> PrintWithSize for locspan::Stripped<T> {
303 fn fmt_with_size(
304 &self,
305 f: &mut fmt::Formatter,
306 options: &Options,
307 indent: usize,
308 sizes: &[Size],
309 index: &mut usize,
310 ) -> fmt::Result {
311 self.0.fmt_with_size(f, options, indent, sizes, index)
312 }
313}
314
315impl<T: PrintWithSize, M> PrintWithSize for locspan::Meta<T, M> {
316 fn fmt_with_size(
317 &self,
318 f: &mut fmt::Formatter,
319 options: &Options,
320 indent: usize,
321 sizes: &[Size],
322 index: &mut usize,
323 ) -> fmt::Result {
324 self.value().fmt_with_size(f, options, indent, sizes, index)
325 }
326}
327
328impl<'a, T: PrintWithSize + ?Sized> PrintWithSize for &'a T {
329 fn fmt_with_size(
330 &self,
331 f: &mut fmt::Formatter,
332 options: &Options,
333 indent: usize,
334 sizes: &[Size],
335 index: &mut usize,
336 ) -> fmt::Result {
337 (**self).fmt_with_size(f, options, indent, sizes, index)
338 }
339}
340
341pub struct Printed<'t, T: ?Sized>(&'t T, Options, usize);
343
344impl<'t, T: Print> fmt::Display for Printed<'t, T> {
345 #[inline(always)]
346 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
347 self.0.fmt_with(f, &self.1, self.2)
348 }
349}
350
351impl Print for bool {
352 #[inline(always)]
353 fn fmt_with(&self, f: &mut fmt::Formatter, _options: &Options, _indent: usize) -> fmt::Result {
354 if *self {
355 f.write_str("true")
356 } else {
357 f.write_str("false")
358 }
359 }
360}
361
362impl Print for crate::NumberBuf {
363 #[inline(always)]
364 fn fmt_with(&self, f: &mut fmt::Formatter, _options: &Options, _indent: usize) -> fmt::Result {
365 fmt::Display::fmt(self, f)
366 }
367}
368
369pub fn string_literal(s: &str, f: &mut fmt::Formatter) -> fmt::Result {
371 use fmt::Display;
372 f.write_str("\"")?;
373
374 for c in s.chars() {
375 match c {
376 '\\' => f.write_str("\\\\")?,
377 '\"' => f.write_str("\\\"")?,
378 '\u{0008}' => f.write_str("\\b")?,
379 '\u{0009}' => f.write_str("\\t")?,
380 '\u{000a}' => f.write_str("\\n")?,
381 '\u{000c}' => f.write_str("\\f")?,
382 '\u{000d}' => f.write_str("\\r")?,
383 '\u{0000}'..='\u{001f}' => {
384 f.write_str("\\u")?;
385
386 let codepoint = c as u32;
387 let d = codepoint & 0x000f;
388 let c = (codepoint & 0x00f0) >> 4;
389 let b = (codepoint & 0x0f00) >> 8;
390 let a = (codepoint & 0xf000) >> 12;
391
392 digit(a).fmt(f)?;
393 digit(b).fmt(f)?;
394 digit(c).fmt(f)?;
395 digit(d).fmt(f)?
396 }
397 _ => c.fmt(f)?,
398 }
399 }
400
401 f.write_str("\"")
402}
403
404fn digit(c: u32) -> char {
405 match c {
406 0x0 => '0',
407 0x1 => '1',
408 0x2 => '2',
409 0x3 => '3',
410 0x4 => '4',
411 0x5 => '5',
412 0x6 => '6',
413 0x7 => '7',
414 0x8 => '8',
415 0x9 => '9',
416 0xa => 'a',
417 0xb => 'b',
418 0xc => 'c',
419 0xd => 'd',
420 0xe => 'e',
421 0xf => 'f',
422 _ => panic!("invalid input: {}", c),
423 }
424}
425
426pub fn printed_string_size(s: &str) -> usize {
428 let mut width = 2;
429
430 for c in s.chars() {
431 width += match c {
432 '\\' | '\"' | '\u{0008}' | '\u{0009}' | '\u{000a}' | '\u{000c}' | '\u{000d}' => 2,
433 '\u{0000}'..='\u{001f}' => 6,
434 _ => 1,
435 }
436 }
437
438 width
439}
440
441impl Print for crate::String {
442 #[inline(always)]
443 fn fmt_with(&self, f: &mut fmt::Formatter, _options: &Options, _indent: usize) -> fmt::Result {
444 string_literal(self, f)
445 }
446}
447
448pub fn print_array<I: IntoIterator>(
449 items: I,
450 f: &mut fmt::Formatter,
451 options: &Options,
452 indent: usize,
453 sizes: &[Size],
454 index: &mut usize,
455) -> fmt::Result
456where
457 I::IntoIter: ExactSizeIterator,
458 I::Item: PrintWithSize,
459{
460 use fmt::Display;
461 let size = sizes[*index];
462 *index += 1;
463
464 f.write_str("[")?;
465
466 let items = items.into_iter();
467 if items.len() == 0 {
468 match size {
469 Size::Expanded => {
470 f.write_str("\n")?;
471 options.indent.by(indent).fmt(f)?;
472 }
473 Size::Width(_) => Spaces(options.array_empty).fmt(f)?,
474 }
475 } else {
476 match size {
477 Size::Expanded => {
478 f.write_str("\n")?;
479
480 for (i, item) in items.enumerate() {
481 if i > 0 {
482 Spaces(options.array_before_comma).fmt(f)?;
483 f.write_str(",\n")?
484 }
485
486 options.indent.by(indent + 1).fmt(f)?;
487 item.fmt_with_size(f, options, indent + 1, sizes, index)?
488 }
489
490 f.write_str("\n")?;
491 options.indent.by(indent).fmt(f)?;
492 }
493 Size::Width(_) => {
494 Spaces(options.array_begin).fmt(f)?;
495 for (i, item) in items.enumerate() {
496 if i > 0 {
497 Spaces(options.array_before_comma).fmt(f)?;
498 f.write_str(",")?;
499 Spaces(options.array_after_comma).fmt(f)?
500 }
501
502 item.fmt_with_size(f, options, indent + 1, sizes, index)?
503 }
504 Spaces(options.array_end).fmt(f)?
505 }
506 }
507 }
508
509 f.write_str("]")
510}
511
512impl<T: PrintWithSize> PrintWithSize for Vec<T> {
513 #[inline(always)]
514 fn fmt_with_size(
515 &self,
516 f: &mut fmt::Formatter,
517 options: &Options,
518 indent: usize,
519 sizes: &[Size],
520 index: &mut usize,
521 ) -> fmt::Result {
522 print_array(self, f, options, indent, sizes, index)
523 }
524}
525
526pub fn print_object<'a, V, I: IntoIterator<Item = (&'a str, V)>>(
527 entries: I,
528 f: &mut fmt::Formatter,
529 options: &Options,
530 indent: usize,
531 sizes: &[Size],
532 index: &mut usize,
533) -> fmt::Result
534where
535 I::IntoIter: ExactSizeIterator,
536 V: PrintWithSize,
537{
538 use fmt::Display;
539 let size = sizes[*index];
540 *index += 1;
541
542 f.write_str("{")?;
543
544 let entries = entries.into_iter();
545 if entries.len() == 0 {
546 match size {
547 Size::Expanded => {
548 f.write_str("\n")?;
549 options.indent.by(indent).fmt(f)?;
550 }
551 Size::Width(_) => Spaces(options.object_empty).fmt(f)?,
552 }
553 } else {
554 match size {
555 Size::Expanded => {
556 f.write_str("\n")?;
557
558 for (i, (key, value)) in entries.enumerate() {
559 if i > 0 {
560 Spaces(options.object_before_comma).fmt(f)?;
561 f.write_str(",\n")?
562 }
563
564 options.indent.by(indent + 1).fmt(f)?;
565
566 string_literal(key, f)?;
567 Spaces(options.object_before_colon).fmt(f)?;
568 f.write_str(":")?;
569 Spaces(options.object_after_colon).fmt(f)?;
570
571 value.fmt_with_size(f, options, indent + 1, sizes, index)?
572 }
573
574 f.write_str("\n")?;
575 options.indent.by(indent).fmt(f)?;
576 }
577 Size::Width(_) => {
578 Spaces(options.object_begin).fmt(f)?;
579 for (i, (key, value)) in entries.enumerate() {
580 if i > 0 {
581 Spaces(options.object_before_comma).fmt(f)?;
582 f.write_str(",")?;
583 Spaces(options.object_after_comma).fmt(f)?
584 }
585
586 string_literal(key, f)?;
587 Spaces(options.object_before_colon).fmt(f)?;
588 f.write_str(":")?;
589 Spaces(options.object_after_colon).fmt(f)?;
590
591 value.fmt_with_size(f, options, indent + 1, sizes, index)?
592 }
593 Spaces(options.object_end).fmt(f)?
594 }
595 }
596 }
597
598 f.write_str("}")
599}
600
601impl PrintWithSize for crate::Object {
602 #[inline(always)]
603 fn fmt_with_size(
604 &self,
605 f: &mut fmt::Formatter,
606 options: &Options,
607 indent: usize,
608 sizes: &[Size],
609 index: &mut usize,
610 ) -> fmt::Result {
611 print_object(
612 self.iter().map(|e| (e.key.as_str(), &e.value)),
613 f,
614 options,
615 indent,
616 sizes,
617 index,
618 )
619 }
620}
621
622pub trait PrecomputeSize {
623 fn pre_compute_size(&self, options: &Options, sizes: &mut Vec<Size>) -> Size;
624}
625
626impl PrecomputeSize for bool {
627 #[inline(always)]
628 fn pre_compute_size(&self, _options: &Options, _sizes: &mut Vec<Size>) -> Size {
629 if *self {
630 Size::Width(4)
631 } else {
632 Size::Width(5)
633 }
634 }
635}
636
637impl PrecomputeSize for crate::Value {
638 fn pre_compute_size(&self, options: &Options, sizes: &mut Vec<Size>) -> Size {
639 match self {
640 crate::Value::Null => Size::Width(4),
641 crate::Value::Boolean(b) => b.pre_compute_size(options, sizes),
642 crate::Value::Number(n) => Size::Width(n.as_str().len()),
643 crate::Value::String(s) => Size::Width(printed_string_size(s)),
644 crate::Value::Array(a) => pre_compute_array_size(a, options, sizes),
645 crate::Value::Object(o) => pre_compute_object_size(
646 o.iter().map(|e| (e.key.as_str(), &e.value)),
647 options,
648 sizes,
649 ),
650 }
651 }
652}
653
654impl<'a, T: PrecomputeSize + ?Sized> PrecomputeSize for &'a T {
655 fn pre_compute_size(&self, options: &Options, sizes: &mut Vec<Size>) -> Size {
656 (**self).pre_compute_size(options, sizes)
657 }
658}
659
660impl<T: PrecomputeSize> PrecomputeSize for locspan::Stripped<T> {
661 fn pre_compute_size(&self, options: &Options, sizes: &mut Vec<Size>) -> Size {
662 self.0.pre_compute_size(options, sizes)
663 }
664}
665
666impl<T: PrecomputeSize, M> PrecomputeSize for locspan::Meta<T, M> {
667 fn pre_compute_size(&self, options: &Options, sizes: &mut Vec<Size>) -> Size {
668 self.value().pre_compute_size(options, sizes)
669 }
670}
671
672pub fn pre_compute_array_size<I: IntoIterator>(
673 items: I,
674 options: &Options,
675 sizes: &mut Vec<Size>,
676) -> Size
677where
678 I::Item: PrecomputeSize,
679{
680 let index = sizes.len();
681 sizes.push(Size::Width(0));
682
683 let mut size = Size::Width(2 + options.object_begin + options.object_end);
684
685 let mut len = 0;
686 for (i, item) in items.into_iter().enumerate() {
687 if i > 0 {
688 size.add(Size::Width(
689 1 + options.array_before_comma + options.array_after_comma,
690 ));
691 }
692
693 size.add(item.pre_compute_size(options, sizes));
694 len += 1
695 }
696
697 let size = match size {
698 Size::Expanded => Size::Expanded,
699 Size::Width(width) => match options.array_limit {
700 None => Size::Width(width),
701 Some(Limit::Always) => Size::Expanded,
702 Some(Limit::Item(i)) => {
703 if len > i {
704 Size::Expanded
705 } else {
706 Size::Width(width)
707 }
708 }
709 Some(Limit::ItemOrWidth(i, w)) => {
710 if len > i || width > w {
711 Size::Expanded
712 } else {
713 Size::Width(width)
714 }
715 }
716 Some(Limit::Width(w)) => {
717 if width > w {
718 Size::Expanded
719 } else {
720 Size::Width(width)
721 }
722 }
723 },
724 };
725
726 sizes[index] = size;
727 size
728}
729
730pub fn pre_compute_object_size<'a, V, I: IntoIterator<Item = (&'a str, V)>>(
731 entries: I,
732 options: &Options,
733 sizes: &mut Vec<Size>,
734) -> Size
735where
736 V: PrecomputeSize,
737{
738 let index = sizes.len();
739 sizes.push(Size::Width(0));
740
741 let mut size = Size::Width(2 + options.object_begin + options.object_end);
742
743 let mut len = 0;
744 for (i, (key, value)) in entries.into_iter().enumerate() {
745 if i > 0 {
746 size.add(Size::Width(
747 1 + options.object_before_comma + options.object_after_comma,
748 ));
749 }
750
751 size.add(Size::Width(
752 printed_string_size(key) + 1 + options.object_before_colon + options.object_after_colon,
753 ));
754 size.add(value.pre_compute_size(options, sizes));
755 len += 1;
756 }
757
758 let size = match size {
759 Size::Expanded => Size::Expanded,
760 Size::Width(width) => match options.object_limit {
761 None => Size::Width(width),
762 Some(Limit::Always) => Size::Expanded,
763 Some(Limit::Item(i)) => {
764 if len > i {
765 Size::Expanded
766 } else {
767 Size::Width(width)
768 }
769 }
770 Some(Limit::ItemOrWidth(i, w)) => {
771 if len > i || width > w {
772 Size::Expanded
773 } else {
774 Size::Width(width)
775 }
776 }
777 Some(Limit::Width(w)) => {
778 if width > w {
779 Size::Expanded
780 } else {
781 Size::Width(width)
782 }
783 }
784 },
785 };
786
787 sizes[index] = size;
788 size
789}
790
791impl Print for crate::Value {
792 fn fmt_with(&self, f: &mut fmt::Formatter, options: &Options, indent: usize) -> fmt::Result {
793 match self {
794 Self::Null => f.write_str("null"),
795 Self::Boolean(b) => b.fmt_with(f, options, indent),
796 Self::Number(n) => n.fmt_with(f, options, indent),
797 Self::String(s) => s.fmt_with(f, options, indent),
798 Self::Array(a) => {
799 let mut sizes =
800 Vec::with_capacity(self.count(|_, v| v.is_array() || v.is_object()));
801 self.pre_compute_size(options, &mut sizes);
802 let mut index = 0;
803 a.fmt_with_size(f, options, indent, &sizes, &mut index)
804 }
805 Self::Object(o) => {
806 let mut sizes =
807 Vec::with_capacity(self.count(|_, v| v.is_array() || v.is_object()));
808 self.pre_compute_size(options, &mut sizes);
809 let mut index = 0;
810 o.fmt_with_size(f, options, indent, &sizes, &mut index)
811 }
812 }
813 }
814}
815
816impl PrintWithSize for crate::Value {
817 fn fmt_with_size(
818 &self,
819 f: &mut fmt::Formatter,
820 options: &Options,
821 indent: usize,
822 sizes: &[Size],
823 index: &mut usize,
824 ) -> fmt::Result {
825 match self {
826 Self::Null => f.write_str("null"),
827 Self::Boolean(b) => b.fmt_with(f, options, indent),
828 Self::Number(n) => n.fmt_with(f, options, indent),
829 Self::String(s) => s.fmt_with(f, options, indent),
830 Self::Array(a) => a.fmt_with_size(f, options, indent, sizes, index),
831 Self::Object(o) => o.fmt_with_size(f, options, indent, sizes, index),
832 }
833 }
834}