json_pretty/
lib.rs

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                    //println!("',' found'");
76                    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}