|
1 | 1 | use JsonValue; |
2 | 2 |
|
3 | | -pub struct Generator { |
4 | | - pub minify: bool, |
5 | | - code: String, |
6 | | - dent: u16, |
7 | | - spaces_per_indent: u16, |
8 | | -} |
| 3 | +pub trait Generator { |
| 4 | + fn new_line(&mut self) {} |
9 | 5 |
|
10 | | -impl Generator { |
11 | | - pub fn new(minify: bool, spaces: u16) -> Self { |
12 | | - Generator { |
13 | | - minify: minify, |
14 | | - code: String::new(), |
15 | | - dent: 0, |
16 | | - spaces_per_indent: spaces |
| 6 | + fn write(&mut self, slice: &[u8]); |
| 7 | + |
| 8 | + fn write_min(&mut self, slice: &[u8], minslice: &[u8]); |
| 9 | + |
| 10 | + fn write_char(&mut self, ch: u8); |
| 11 | + |
| 12 | + fn indent(&mut self) {} |
| 13 | + |
| 14 | + fn dedent(&mut self) {} |
| 15 | + |
| 16 | + fn write_string(&mut self, string: &str) { |
| 17 | + self.write_char(b'"'); |
| 18 | + |
| 19 | + for ch in string.bytes() { |
| 20 | + match ch { |
| 21 | + b'\\' | b'"' => { |
| 22 | + self.write_char(b'\\'); |
| 23 | + self.write_char(ch); |
| 24 | + }, |
| 25 | + b'\n' => self.write(b"\\n"), |
| 26 | + b'\r' => self.write(b"\\r"), |
| 27 | + b'\t' => self.write(b"\\t"), |
| 28 | + 0xC => self.write(b"\\f"), |
| 29 | + 0x8 => self.write(b"\\b"), |
| 30 | + _ => self.write_char(ch) |
| 31 | + } |
17 | 32 | } |
| 33 | + |
| 34 | + self.write_char(b'"'); |
18 | 35 | } |
19 | 36 |
|
20 | | - pub fn new_line(&mut self) { |
21 | | - if !self.minify { |
22 | | - self.code.push('\n'); |
23 | | - for _ in 0..(self.dent * self.spaces_per_indent) { |
24 | | - self.code.push(' '); |
25 | | - } |
| 37 | + fn write_digits_from_u64(&mut self, mut num: u64, length: &mut u8) { |
| 38 | + let digit = (num % 10) as u8; |
| 39 | + num /= 10; |
| 40 | + if num > 0 { |
| 41 | + self.write_digits_from_u64(num, length); |
26 | 42 | } |
| 43 | + *length += 1; |
| 44 | + self.write_char(digit + b'0'); |
27 | 45 | } |
28 | 46 |
|
29 | | - pub fn write_json(&mut self, json: &JsonValue) { |
30 | | - match *json { |
31 | | - JsonValue::String(ref string) => { |
32 | | - self.write_char('"'); |
33 | | - |
34 | | - for ch in string.chars() { |
35 | | - match ch { |
36 | | - '\\' | '"' => { |
37 | | - self.write_char('\\'); |
38 | | - self.write_char(ch); |
39 | | - }, |
40 | | - '\n' => self.write("\\n"), |
41 | | - '\r' => self.write("\\r"), |
42 | | - '\t' => self.write("\\t"), |
43 | | - '\u{000C}' => self.write("\\f"), |
44 | | - '\u{0008}' => self.write("\\b"), |
45 | | - _ => self.write_char(ch) |
46 | | - } |
47 | | - } |
| 47 | + fn write_number(&mut self, mut num: f64) { |
| 48 | + let mut length = 0; |
| 49 | + if num < 0.0 { |
| 50 | + num = -num; |
| 51 | + self.write_char(b'-'); |
| 52 | + } |
48 | 53 |
|
49 | | - self.write_char('"'); |
50 | | - }, |
51 | | - JsonValue::Number(ref number) => self.write(&number.to_string()), |
52 | | - JsonValue::Boolean(ref value) => self.write(if *value { "true" } else { "false" }), |
53 | | - JsonValue::Null => self.write("null"), |
| 54 | + self.write_digits_from_u64(num as u64, &mut length); |
| 55 | + |
| 56 | + let mut fract = num.fract(); |
| 57 | + if fract < 1e-10 { |
| 58 | + return; |
| 59 | + } |
| 60 | + |
| 61 | + fract *= 10.0; |
| 62 | + self.write_char(b'.'); |
| 63 | + self.write_char((fract as u8) + b'0'); |
| 64 | + fract = fract.fract(); |
| 65 | + length += 2; |
| 66 | + |
| 67 | + while length < 17 && fract > 0.01 { |
| 68 | + fract *= 10.0; |
| 69 | + self.write_char((fract as u8) + b'0'); |
| 70 | + fract = fract.fract(); |
| 71 | + length += 1; |
| 72 | + } |
| 73 | + } |
| 74 | + |
| 75 | + fn write_json(&mut self, json: &JsonValue) { |
| 76 | + match *json { |
| 77 | + JsonValue::String(ref string) => self.write_string(string), |
| 78 | + JsonValue::Number(ref number) => self.write_number(*number), |
| 79 | + JsonValue::Boolean(ref value) => self.write(if *value { b"true" } else { b"false" }), |
| 80 | + JsonValue::Null => self.write(b"null"), |
54 | 81 | JsonValue::Array(ref array) => { |
55 | | - self.write_char('['); |
| 82 | + self.write_char(b'['); |
56 | 83 | self.indent(); |
57 | 84 | let mut first = true; |
58 | 85 | for item in array { |
59 | 86 | if first { |
60 | 87 | first = false; |
61 | 88 | self.new_line(); |
62 | 89 | } else { |
63 | | - self.write(","); |
| 90 | + self.write(b","); |
64 | 91 | self.new_line(); |
65 | 92 | } |
66 | 93 | self.write_json(item); |
67 | 94 | } |
68 | 95 | self.dedent(); |
69 | 96 | self.new_line(); |
70 | | - self.write_char(']'); |
| 97 | + self.write_char(b']'); |
71 | 98 | }, |
72 | 99 | JsonValue::Object(ref object) => { |
73 | | - self.write_char('{'); |
| 100 | + self.write_char(b'{'); |
74 | 101 | self.indent(); |
75 | 102 | let mut first = true; |
76 | 103 | for (key, value) in object.iter() { |
77 | 104 | if first { |
78 | 105 | first = false; |
79 | 106 | self.new_line(); |
80 | 107 | } else { |
81 | | - self.write(","); |
| 108 | + self.write(b","); |
82 | 109 | self.new_line(); |
83 | 110 | } |
84 | | - self.write(&format!("{:?}", key)); |
85 | | - self.write_min(": ", ":"); |
| 111 | + self.write_string(key); |
| 112 | + self.write_min(b": ", b":"); |
86 | 113 | self.write_json(value); |
87 | 114 | } |
88 | 115 | self.dedent(); |
89 | 116 | self.new_line(); |
90 | | - self.write_char('}'); |
| 117 | + self.write_char(b'}'); |
91 | 118 | } |
92 | 119 | } |
93 | 120 | } |
94 | 121 |
|
95 | | - pub fn write(&mut self, slice: &str) { |
96 | | - self.code.push_str(slice); |
| 122 | + fn consume(self) -> String; |
| 123 | +} |
| 124 | + |
| 125 | +pub struct DumpGenerator { |
| 126 | + code: Vec<u8>, |
| 127 | +} |
| 128 | + |
| 129 | +impl DumpGenerator { |
| 130 | + pub fn new() -> Self { |
| 131 | + DumpGenerator { |
| 132 | + code: Vec::with_capacity(1024), |
| 133 | + } |
| 134 | + } |
| 135 | +} |
| 136 | + |
| 137 | +impl Generator for DumpGenerator { |
| 138 | + fn write(&mut self, slice: &[u8]) { |
| 139 | + self.code.extend_from_slice(slice); |
| 140 | + } |
| 141 | + |
| 142 | + fn write_min(&mut self, _: &[u8], minslice: &[u8]) { |
| 143 | + self.code.extend_from_slice(minslice); |
| 144 | + } |
| 145 | + |
| 146 | + fn write_char(&mut self, ch: u8) { |
| 147 | + self.code.push(ch); |
| 148 | + } |
| 149 | + |
| 150 | + fn consume(self) -> String { |
| 151 | + String::from_utf8(self.code).unwrap() |
| 152 | + } |
| 153 | +} |
| 154 | + |
| 155 | +pub struct PrettyGenerator { |
| 156 | + code: Vec<u8>, |
| 157 | + dent: u16, |
| 158 | + spaces_per_indent: u16, |
| 159 | +} |
| 160 | + |
| 161 | +impl PrettyGenerator { |
| 162 | + pub fn new(spaces: u16) -> Self { |
| 163 | + PrettyGenerator { |
| 164 | + code: Vec::with_capacity(1024), |
| 165 | + dent: 0, |
| 166 | + spaces_per_indent: spaces |
| 167 | + } |
97 | 168 | } |
| 169 | +} |
98 | 170 |
|
99 | | - pub fn write_min(&mut self, slice: &str, minslice: &str) { |
100 | | - if self.minify { |
101 | | - self.write(minslice); |
102 | | - } else { |
103 | | - self.write(slice); |
| 171 | +impl Generator for PrettyGenerator { |
| 172 | + fn new_line(&mut self) { |
| 173 | + self.code.push(b'\n'); |
| 174 | + for _ in 0..(self.dent * self.spaces_per_indent) { |
| 175 | + self.code.push(b' '); |
104 | 176 | } |
105 | 177 | } |
106 | 178 |
|
107 | | - pub fn write_char(&mut self, ch: char) { |
| 179 | + fn write(&mut self, slice: &[u8]) { |
| 180 | + self.code.extend_from_slice(slice); |
| 181 | + } |
| 182 | + |
| 183 | + fn write_min(&mut self, slice: &[u8], _: &[u8]) { |
| 184 | + self.code.extend_from_slice(slice); |
| 185 | + } |
| 186 | + |
| 187 | + fn write_char(&mut self, ch: u8) { |
108 | 188 | self.code.push(ch); |
109 | 189 | } |
110 | 190 |
|
111 | | - pub fn indent(&mut self) { |
| 191 | + fn indent(&mut self) { |
112 | 192 | self.dent += 1; |
113 | 193 | } |
114 | 194 |
|
115 | | - pub fn dedent(&mut self) { |
| 195 | + fn dedent(&mut self) { |
116 | 196 | self.dent -= 1; |
117 | 197 | } |
118 | 198 |
|
119 | | - pub fn consume(self) -> String { |
120 | | - self.code |
| 199 | + fn consume(self) -> String { |
| 200 | + String::from_utf8(self.code).unwrap() |
121 | 201 | } |
122 | 202 | } |
0 commit comments