1use std::fmt;
2
3#[derive(Debug)]
4pub struct PrettyFormatter {
5 string: String,
6 indent: i32
7}
8
9impl PrettyFormatter {
10 pub fn from_str(s: &str) -> PrettyFormatter {
11 PrettyFormatter {
12 string: s.to_owned(),
13 indent: 2
14 }
15 }
16
17 pub fn from_string(s: &String) -> PrettyFormatter {
18 PrettyFormatter {
19 string: s.clone(),
20 indent: 2
21 }
22 }
23
24 pub fn indent(&mut self, indent: i32) -> PrettyFormatter {
25 PrettyFormatter {
26 string: self.string.clone(),
27 indent: indent,
28 }
29 }
30
31 pub fn pretty(&self) -> String {
32 let mut result = String::new();
33
34 let mut in_string = false;
35 let mut indent = 0;
36 let mut need_indent = false;
37
38 for ch in self.string.chars() {
39 match ch {
40 '{' => {
41 if need_indent {
42 for _ in 0..indent {
43 result.push(' ');
44 }
45 need_indent = false;
46 }
47 result.push('{');
48 if !in_string {
49 indent += self.indent;
50 result.push('\n');
51 need_indent = true;
52 }
53 },
54 '}' => {
55 if !in_string {
56 result.push('\n');
57 indent -= self.indent;
58 for _ in 0..indent {
59 result.push(' ');
60 }
61 }
62 result.push('}');
63 },
64 '"' => {
65 if need_indent {
66 for _ in 0..indent {
67 result.push(' ');
68 }
69 }
70 result.push('"');
71 in_string = !in_string;
72 need_indent = false;
73 },
74 ',' => {
75 if need_indent {
77 for _ in 0..indent {
78 result.push(' ');
79 }
80 need_indent = false;
81 }
82 result.push(',');
83 if !in_string {
84 result.push('\n');
85 need_indent = true;
86 }
87 },
88 ch @ ' ' | ch @ '\t' => {
89 if in_string {
90 result.push(ch);
91 }else{
92 if need_indent {
93 continue;
94 }else{
95 result.push(ch);
96 }
97 }
98 },
99 '\n' => {
100 if in_string {
101 result.push('\n');
102 }else{
103 need_indent = true;
104 continue;
105 }
106 }
107 c => {
108 if need_indent {
109 for _ in 0..indent {
110 result.push(' ');
111 }
112 }
113 need_indent = false;
114 result.push(c);
115 },
116 }
117 }
118
119 result
120 }
121}
122
123impl fmt::Display for PrettyFormatter {
124 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
125 write!(f, "{}", self.pretty())
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 #[test]
132 fn test_pretty_formatter() {
133 use super::PrettyFormatter;
134
135 let s = r#"{"description": "string for test", "id" : 123, "true" : true, "nest": { "foo" : "bar"}}"#;
136 let formatter = PrettyFormatter::from_str(s);
137 let result = formatter.pretty();
138 println!("s: {}", result);
139 assert_eq!(r#"{
140 "description": "string for test",
141 "id" : 123,
142 "true" : true,
143 "nest": {
144 "foo" : "bar"
145 }
146}"#, result);
147 }
148}