Skip to content

Commit bd65f39

Browse files
authored
Merge pull request #54 from maciejhirsz/0.8.5
0.8.5 closes #51, closes #53
2 parents 07b6866 + 1e486c4 commit bd65f39

File tree

5 files changed

+1152
-748
lines changed

5 files changed

+1152
-748
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "json"
3-
version = "0.8.4"
3+
version = "0.8.5"
44
authors = ["Maciej Hirsz <maciej.hirsz@gmail.com>"]
55
description = "JSON implementation in Rust"
66
repository = "https://github.com/maciejhirsz/json-rust"

src/codegen.rs

Lines changed: 123 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -4,65 +4,79 @@ use JsonValue;
44

55
extern crate itoa;
66

7+
const QU: u8 = b'"';
8+
const BS: u8 = b'\\';
9+
const B: u8 = b'b';
10+
const T: u8 = b't';
11+
const N: u8 = b'n';
12+
const F: u8 = b'f';
13+
const R: u8 = b'r';
14+
const U: u8 = b'u';
15+
716
static ESCAPED: [u8; 256] = [
817
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
9-
0, 0, 0, 0, 0, 0, 0, 0,b'b',b't',b'n', 0,b'f',b'r', 0, 0, // 0
10-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
11-
0, 0,b'"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2
12-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3
13-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4
14-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,b'\\', 0, 0, 0, // 5
15-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6
16-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7
17-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
18-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
19-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
20-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
21-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
22-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
23-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
24-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // F
18+
U, U, U, U, U, U, U, U, B, T, N, U, F, R, U, U, // 0
19+
U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, // 1
20+
0, 0, QU, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2
21+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3
22+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4
23+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, BS, 0, 0, 0, // 5
24+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6
25+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, U, // 7
26+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
27+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
28+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
29+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
30+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
31+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
32+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
33+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // F
2534
];
2635

2736
pub trait Generator {
28-
fn get_buffer(&mut self) -> &mut Vec<u8>;
37+
type T: Write;
2938

30-
fn current_index(&mut self) -> usize {
31-
self.get_buffer().len()
32-
}
39+
fn get_writer(&mut self) -> &mut Self::T;
3340

3441
#[inline(always)]
3542
fn write(&mut self, slice: &[u8]) {
36-
self.get_buffer().extend_from_slice(slice)
43+
self.get_writer().write_all(slice).unwrap();
3744
}
3845

3946
#[inline(always)]
4047
fn write_char(&mut self, ch: u8) {
41-
self.get_buffer().push(ch)
48+
self.get_writer().write_all(&[ch]).unwrap();
4249
}
4350

44-
fn write_min(&mut self, slice: &[u8], minslice: &[u8]);
51+
fn write_min(&mut self, slice: &[u8], min: u8);
4552

4653
fn new_line(&mut self) {}
4754

4855
fn indent(&mut self) {}
4956

5057
fn dedent(&mut self) {}
5158

59+
#[inline(never)]
5260
fn write_string_complex(&mut self, string: &str, mut start: usize) {
61+
self.write(string[ .. start].as_bytes());
62+
5363
for (index, ch) in string.bytes().enumerate().skip(start) {
5464
let escape = ESCAPED[ch as usize];
5565
if escape > 0 {
5666
self.write(string[start .. index].as_bytes());
5767
self.write(&[b'\\', escape]);
5868
start = index + 1;
5969
}
70+
if escape == b'u' {
71+
write!(self.get_writer(), "{:04x}", ch).unwrap();
72+
}
6073
}
6174
self.write(string[start ..].as_bytes());
6275

6376
self.write_char(b'"');
6477
}
6578

79+
#[inline(always)]
6680
fn write_string(&mut self, string: &str) {
6781
self.write_char(b'"');
6882

@@ -76,42 +90,33 @@ pub trait Generator {
7690
self.write_char(b'"');
7791
}
7892

79-
fn write_number(&mut self, mut num: f64) {
93+
fn write_number(&mut self, num: f64) {
8094
match num.classify() {
81-
FpCategory::Nan |
82-
FpCategory::Infinite => {
83-
self.write(b"null");
84-
return;
95+
FpCategory::Normal |
96+
FpCategory::Subnormal => {
97+
if num.fract() == 0.0 && num.abs() < 1e19 {
98+
itoa::write(self.get_writer(), num as i64).unwrap();
99+
} else {
100+
let abs = num.abs();
101+
if abs < 1e-15 || abs > 1e19 {
102+
write!(self.get_writer(), "{:e}", num).unwrap();
103+
} else {
104+
write!(self.get_writer(), "{}", num).unwrap();
105+
}
106+
}
85107
},
86108
FpCategory::Zero => {
87-
self.write(if num.is_sign_negative() { b"-0" } else { b"0" });
88-
return;
109+
if num.is_sign_negative() {
110+
self.write(b"-0");
111+
} else {
112+
self.write_char(b'0');
113+
}
89114
},
90-
_ => {},
91-
}
92-
93-
if num.is_sign_negative() {
94-
num = num.abs();
95-
self.write_char(b'-');
96-
}
97-
98-
let fract = num.fract();
99-
100-
if fract > 0.0 {
101-
if num < 1e-15 {
102-
write!(self.get_buffer(), "{:e}", num).unwrap();
103-
} else {
104-
write!(self.get_buffer(), "{}", num).unwrap();
115+
FpCategory::Nan |
116+
FpCategory::Infinite => {
117+
self.write(b"null");
105118
}
106-
return;
107-
}
108-
109-
if num > 1e19 {
110-
write!(self.get_buffer(), "{:e}", num).unwrap();
111-
return;
112119
}
113-
114-
itoa::write(self.get_buffer(), num as u64).unwrap();
115120
}
116121

117122
fn write_json(&mut self, json: &JsonValue) {
@@ -130,7 +135,7 @@ pub trait Generator {
130135
first = false;
131136
self.new_line();
132137
} else {
133-
self.write(b",");
138+
self.write_char(b',');
134139
self.new_line();
135140
}
136141
self.write_json(item);
@@ -148,11 +153,11 @@ pub trait Generator {
148153
first = false;
149154
self.new_line();
150155
} else {
151-
self.write(b",");
156+
self.write_char(b',');
152157
self.new_line();
153158
}
154159
self.write_string(key);
155-
self.write_min(b": ", b":");
160+
self.write_min(b": ", b':');
156161
self.write_json(value);
157162
}
158163
self.dedent();
@@ -161,8 +166,6 @@ pub trait Generator {
161166
}
162167
}
163168
}
164-
165-
fn consume(self) -> String;
166169
}
167170

168171
pub struct DumpGenerator {
@@ -175,21 +178,35 @@ impl DumpGenerator {
175178
code: Vec::with_capacity(1024),
176179
}
177180
}
181+
182+
pub fn consume(self) -> String {
183+
// Original strings were unicode, numbers are all ASCII,
184+
// therefore this is safe.
185+
unsafe { String::from_utf8_unchecked(self.code) }
186+
}
178187
}
179188

180189
impl Generator for DumpGenerator {
190+
type T = Vec<u8>;
191+
181192
#[inline(always)]
182-
fn get_buffer(&mut self) -> &mut Vec<u8> {
183-
&mut self.code
193+
fn write(&mut self, slice: &[u8]) {
194+
self.code.extend_from_slice(slice)
184195
}
185196

186197
#[inline(always)]
187-
fn write_min(&mut self, _: &[u8], minslice: &[u8]) {
188-
self.code.extend_from_slice(minslice);
198+
fn write_char(&mut self, ch: u8) {
199+
self.code.push(ch)
200+
}
201+
202+
#[inline(always)]
203+
fn get_writer(&mut self) -> &mut Vec<u8> {
204+
&mut self.code
189205
}
190206

191-
fn consume(self) -> String {
192-
String::from_utf8(self.code).unwrap()
207+
#[inline(always)]
208+
fn write_min(&mut self, _: &[u8], min: u8) {
209+
self.code.push(min);
193210
}
194211
}
195212

@@ -207,16 +224,32 @@ impl PrettyGenerator {
207224
spaces_per_indent: spaces
208225
}
209226
}
227+
228+
pub fn consume(self) -> String {
229+
unsafe { String::from_utf8_unchecked(self.code) }
230+
}
210231
}
211232

212233
impl Generator for PrettyGenerator {
234+
type T = Vec<u8>;
235+
213236
#[inline(always)]
214-
fn get_buffer(&mut self) -> &mut Vec<u8> {
237+
fn write(&mut self, slice: &[u8]) {
238+
self.code.extend_from_slice(slice)
239+
}
240+
241+
#[inline(always)]
242+
fn write_char(&mut self, ch: u8) {
243+
self.code.push(ch)
244+
}
245+
246+
#[inline(always)]
247+
fn get_writer(&mut self) -> &mut Vec<u8> {
215248
&mut self.code
216249
}
217250

218251
#[inline(always)]
219-
fn write_min(&mut self, slice: &[u8], _: &[u8]) {
252+
fn write_min(&mut self, slice: &[u8], _: u8) {
220253
self.code.extend_from_slice(slice);
221254
}
222255

@@ -234,8 +267,30 @@ impl Generator for PrettyGenerator {
234267
fn dedent(&mut self) {
235268
self.dent -= 1;
236269
}
270+
}
271+
272+
pub struct WriterGenerator<'a, W: 'a + Write> {
273+
writer: &'a mut W
274+
}
275+
276+
impl<'a, W> WriterGenerator<'a, W> where W: 'a + Write {
277+
pub fn new(writer: &'a mut W) -> Self {
278+
WriterGenerator {
279+
writer: writer
280+
}
281+
}
282+
}
237283

238-
fn consume(self) -> String {
239-
String::from_utf8(self.code).unwrap()
284+
impl<'a, W> Generator for WriterGenerator<'a, W> where W: Write {
285+
type T = W;
286+
287+
#[inline(always)]
288+
fn get_writer(&mut self) -> &mut W {
289+
&mut self.writer
290+
}
291+
292+
#[inline(always)]
293+
fn write_min(&mut self, _: &[u8], min: u8) {
294+
self.writer.write_all(&[min]).unwrap();
240295
}
241296
}

src/lib.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,9 @@ pub use value::JsonValue::Null;
209209
pub type JsonResult<T> = Result<T, JsonError>;
210210

211211
pub use parser::parse;
212-
use codegen::{ Generator, PrettyGenerator, DumpGenerator };
212+
use codegen::{ Generator, PrettyGenerator, DumpGenerator, WriterGenerator };
213213

214+
use std::io::Write;
214215
use std::collections::HashMap;
215216
use std::collections::BTreeMap;
216217
use std::fmt;
@@ -233,6 +234,12 @@ impl JsonValue {
233234
gen.write_json(self);
234235
gen.consume()
235236
}
237+
238+
/// Dumps the JSON as byte stream into an instance of `std::io::Write`.
239+
pub fn to_writer<W: Write>(&self, writer: &mut W) {
240+
let mut gen = WriterGenerator::new(writer);
241+
gen.write_json(self);
242+
}
236243
}
237244

238245
/// Implements formatting

0 commit comments

Comments
 (0)