Skip to content

Commit 9173efd

Browse files
committed
#51 implement a to_writer method
1 parent ac4cb89 commit 9173efd

File tree

3 files changed

+111
-36
lines changed

3 files changed

+111
-36
lines changed

src/codegen.rs

Lines changed: 91 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,41 +4,48 @@ use JsonValue;
44

55
extern crate itoa;
66

7+
const _Q: u8 = b'"';
8+
const _S: 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, _Q, 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, _S, 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(&[ch]).unwrap();
4249
}
4350

4451
fn write_min(&mut self, slice: &[u8], min: u8);
@@ -49,6 +56,7 @@ pub trait Generator {
4956

5057
fn dedent(&mut self) {}
5158

59+
#[inline(never)]
5260
fn write_string_complex(&mut self, string: &str, mut start: usize) {
5361
for (index, ch) in string.bytes().enumerate().skip(start) {
5462
let escape = ESCAPED[ch as usize];
@@ -82,13 +90,13 @@ pub trait Generator {
8290
FpCategory::Normal |
8391
FpCategory::Subnormal => {
8492
if num.fract() == 0.0 && num.abs() < 1e19 {
85-
itoa::write(self.get_buffer(), num as i64).unwrap();
93+
itoa::write(self.get_writer(), num as i64).unwrap();
8694
} else {
8795
let abs = num.abs();
8896
if abs < 1e-15 || abs > 1e19 {
89-
write!(self.get_buffer(), "{:e}", num).unwrap();
97+
write!(self.get_writer(), "{:e}", num).unwrap();
9098
} else {
91-
write!(self.get_buffer(), "{}", num).unwrap();
99+
write!(self.get_writer(), "{}", num).unwrap();
92100
}
93101
}
94102
},
@@ -153,8 +161,6 @@ pub trait Generator {
153161
}
154162
}
155163
}
156-
157-
fn consume(self) -> String;
158164
}
159165

160166
pub struct DumpGenerator {
@@ -167,22 +173,34 @@ impl DumpGenerator {
167173
code: Vec::with_capacity(1024),
168174
}
169175
}
176+
177+
pub fn consume(self) -> String {
178+
String::from_utf8(self.code).unwrap()
179+
}
170180
}
171181

172182
impl Generator for DumpGenerator {
183+
type T = Vec<u8>;
184+
185+
#[inline(always)]
186+
fn write(&mut self, slice: &[u8]) {
187+
self.code.extend_from_slice(slice)
188+
}
189+
173190
#[inline(always)]
174-
fn get_buffer(&mut self) -> &mut Vec<u8> {
191+
fn write_char(&mut self, ch: u8) {
192+
self.code.push(ch)
193+
}
194+
195+
#[inline(always)]
196+
fn get_writer(&mut self) -> &mut Vec<u8> {
175197
&mut self.code
176198
}
177199

178200
#[inline(always)]
179201
fn write_min(&mut self, _: &[u8], min: u8) {
180202
self.code.push(min);
181203
}
182-
183-
fn consume(self) -> String {
184-
String::from_utf8(self.code).unwrap()
185-
}
186204
}
187205

188206
pub struct PrettyGenerator {
@@ -199,11 +217,27 @@ impl PrettyGenerator {
199217
spaces_per_indent: spaces
200218
}
201219
}
220+
221+
pub fn consume(self) -> String {
222+
String::from_utf8(self.code).unwrap()
223+
}
202224
}
203225

204226
impl Generator for PrettyGenerator {
227+
type T = Vec<u8>;
228+
205229
#[inline(always)]
206-
fn get_buffer(&mut self) -> &mut Vec<u8> {
230+
fn write(&mut self, slice: &[u8]) {
231+
self.code.extend_from_slice(slice)
232+
}
233+
234+
#[inline(always)]
235+
fn write_char(&mut self, ch: u8) {
236+
self.code.push(ch)
237+
}
238+
239+
#[inline(always)]
240+
fn get_writer(&mut self) -> &mut Vec<u8> {
207241
&mut self.code
208242
}
209243

@@ -226,8 +260,30 @@ impl Generator for PrettyGenerator {
226260
fn dedent(&mut self) {
227261
self.dent -= 1;
228262
}
263+
}
229264

230-
fn consume(self) -> String {
231-
String::from_utf8(self.code).unwrap()
265+
pub struct WriterGenerator<'a, W: 'a + Write> {
266+
writer: &'a mut W
267+
}
268+
269+
impl<'a, W> WriterGenerator<'a, W> where W: 'a + Write {
270+
pub fn new(writer: &'a mut W) -> Self {
271+
WriterGenerator {
272+
writer: writer
273+
}
274+
}
275+
}
276+
277+
impl<'a, W> Generator for WriterGenerator<'a, W> where W: Write {
278+
type T = W;
279+
280+
#[inline(always)]
281+
fn get_writer(&mut self) -> &mut W {
282+
&mut self.writer
283+
}
284+
285+
#[inline(always)]
286+
fn write_min(&mut self, _: &[u8], min: u8) {
287+
self.writer.write(&[min]).unwrap();
232288
}
233289
}

src/lib.rs

Lines changed: 7 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,11 @@ impl JsonValue {
233234
gen.write_json(self);
234235
gen.consume()
235236
}
237+
238+
pub fn to_writer<W: Write>(&self, writer: &mut W) {
239+
let mut gen = WriterGenerator::new(writer);
240+
gen.write_json(self);
241+
}
236242
}
237243

238244
/// Implements formatting

tests/lib.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -873,3 +873,16 @@ fn error_unexpected_token() {
873873

874874
assert_eq!(format!("{}", err), "Unexpected character: ] at (4:3)");
875875
}
876+
877+
#[test]
878+
fn writer_generator() {
879+
let data = object!{
880+
"foo" => array!["bar", 100, true]
881+
};
882+
883+
let mut buf = Vec::new();
884+
885+
data.to_writer(&mut buf);
886+
887+
assert_eq!(String::from_utf8(buf).unwrap(), r#"{"foo":["bar",100,true]}"#);
888+
}

0 commit comments

Comments
 (0)