Skip to content

Commit 1028120

Browse files
committed
Parameterize indent in PrettyEncoder
1 parent 20b3313 commit 1028120

File tree

1 file changed

+85
-18
lines changed

1 file changed

+85
-18
lines changed

src/libserialize/json.rs

Lines changed: 85 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -595,13 +595,23 @@ impl<'a> ::Encoder<io::IoError> for Encoder<'a> {
595595
/// compact data
596596
pub struct PrettyEncoder<'a> {
597597
writer: &'a mut io::Writer,
598+
curr_indent: uint,
598599
indent: uint,
599600
}
600601

601602
impl<'a> PrettyEncoder<'a> {
602603
/// Creates a new encoder whose output will be written to the specified writer
603604
pub fn new<'a>(writer: &'a mut io::Writer) -> PrettyEncoder<'a> {
604-
PrettyEncoder { writer: writer, indent: 0 }
605+
PrettyEncoder { writer: writer, curr_indent: 0, indent: 2, }
606+
}
607+
608+
/// Set the number of spaces to indent for each level.
609+
/// This is safe to set during encoding.
610+
pub fn set_indent<'a>(&mut self, indent: uint) {
611+
// self.indent very well could be 0 so we need to use checked division.
612+
let level = self.curr_indent.checked_div(&self.indent).unwrap_or(0);
613+
self.indent = indent;
614+
self.curr_indent = level * self.indent;
605615
}
606616
}
607617

@@ -656,15 +666,15 @@ impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
656666
if cnt == 0 {
657667
escape_str(self.writer, name)
658668
} else {
659-
self.indent += 2;
669+
self.curr_indent += self.indent;
660670
try!(write!(self.writer, "[\n"));
661-
try!(spaces(self.writer, self.indent));
671+
try!(spaces(self.writer, self.curr_indent));
662672
try!(escape_str(self.writer, name));
663673
try!(write!(self.writer, ",\n"));
664674
try!(f(self));
665-
self.indent -= 2;
675+
self.curr_indent -= self.indent;
666676
try!(write!(self.writer, "\n"));
667-
try!(spaces(self.writer, self.indent));
677+
try!(spaces(self.writer, self.curr_indent));
668678
write!(self.writer, "]")
669679
}
670680
}
@@ -675,7 +685,7 @@ impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
675685
if idx != 0 {
676686
try!(write!(self.writer, ",\n"));
677687
}
678-
try!(spaces(self.writer, self.indent));
688+
try!(spaces(self.writer, self.curr_indent));
679689
f(self)
680690
}
681691

@@ -703,11 +713,11 @@ impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
703713
write!(self.writer, "{{}}")
704714
} else {
705715
try!(write!(self.writer, "{{"));
706-
self.indent += 2;
716+
self.curr_indent += self.indent;
707717
try!(f(self));
708-
self.indent -= 2;
718+
self.curr_indent -= self.indent;
709719
try!(write!(self.writer, "\n"));
710-
try!(spaces(self.writer, self.indent));
720+
try!(spaces(self.writer, self.curr_indent));
711721
write!(self.writer, "}}")
712722
}
713723
}
@@ -721,7 +731,7 @@ impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
721731
} else {
722732
try!(write!(self.writer, ",\n"));
723733
}
724-
try!(spaces(self.writer, self.indent));
734+
try!(spaces(self.writer, self.curr_indent));
725735
try!(escape_str(self.writer, name));
726736
try!(write!(self.writer, ": "));
727737
f(self)
@@ -765,11 +775,11 @@ impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
765775
write!(self.writer, "[]")
766776
} else {
767777
try!(write!(self.writer, "["));
768-
self.indent += 2;
778+
self.curr_indent += self.indent;
769779
try!(f(self));
770-
self.indent -= 2;
780+
self.curr_indent -= self.indent;
771781
try!(write!(self.writer, "\n"));
772-
try!(spaces(self.writer, self.indent));
782+
try!(spaces(self.writer, self.curr_indent));
773783
write!(self.writer, "]")
774784
}
775785
}
@@ -782,7 +792,7 @@ impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
782792
} else {
783793
try!(write!(self.writer, ",\n"));
784794
}
785-
try!(spaces(self.writer, self.indent));
795+
try!(spaces(self.writer, self.curr_indent));
786796
f(self)
787797
}
788798

@@ -793,11 +803,11 @@ impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
793803
write!(self.writer, "{{}}")
794804
} else {
795805
try!(write!(self.writer, "{{"));
796-
self.indent += 2;
806+
self.curr_indent += self.indent;
797807
try!(f(self));
798-
self.indent -= 2;
808+
self.curr_indent -= self.indent;
799809
try!(write!(self.writer, "\n"));
800-
try!(spaces(self.writer, self.indent));
810+
try!(spaces(self.writer, self.curr_indent));
801811
write!(self.writer, "}}")
802812
}
803813
}
@@ -810,7 +820,7 @@ impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
810820
} else {
811821
try!(write!(self.writer, ",\n"));
812822
}
813-
try!(spaces(self.writer, self.indent));
823+
try!(spaces(self.writer, self.curr_indent));
814824
// ref #12967, make sure to wrap a key in double quotes,
815825
// in the event that its of a type that omits them (eg numbers)
816826
let mut buf = MemWriter::new();
@@ -3197,6 +3207,63 @@ mod tests {
31973207
}
31983208
}
31993209

3210+
#[test]
3211+
fn test_prettyencoder_indent_level_param() {
3212+
use std::str::from_utf8;
3213+
use std::io::MemWriter;
3214+
use std::collections::TreeMap;
3215+
3216+
let mut tree = TreeMap::new();
3217+
3218+
tree.insert("hello".into_string(), String("guten tag".into_string()));
3219+
tree.insert("goodbye".into_string(), String("sayonara".into_string()));
3220+
3221+
let json = List(
3222+
// The following layout below should look a lot like
3223+
// the pretty-printed JSON (indent * x)
3224+
vec!
3225+
( // 0x
3226+
String("greetings".into_string()), // 1x
3227+
Object(tree), // 1x + 2x + 2x + 1x
3228+
) // 0x
3229+
// End JSON list (7 lines)
3230+
);
3231+
3232+
// Helper function for counting indents
3233+
fn indents(source: &str) -> uint {
3234+
let trimmed = source.trim_left_chars(' ');
3235+
source.len() - trimmed.len()
3236+
}
3237+
3238+
// Test up to 4 spaces of indents (more?)
3239+
for i in range(0, 4u) {
3240+
let mut writer = MemWriter::new();
3241+
{
3242+
let ref mut encoder = PrettyEncoder::new(&mut writer);
3243+
encoder.set_indent(i);
3244+
json.encode(encoder).unwrap();
3245+
}
3246+
3247+
let bytes = writer.unwrap();
3248+
let printed = from_utf8(bytes.as_slice()).unwrap();
3249+
3250+
// Check for indents at each line
3251+
let lines: Vec<&str> = printed.lines().collect();
3252+
assert_eq!(lines.len(), 7); // JSON should be 7 lines
3253+
3254+
assert_eq!(indents(lines[0]), 0 * i); // [
3255+
assert_eq!(indents(lines[1]), 1 * i); // "greetings",
3256+
assert_eq!(indents(lines[2]), 1 * i); // {
3257+
assert_eq!(indents(lines[3]), 2 * i); // "hello": "guten tag",
3258+
assert_eq!(indents(lines[4]), 2 * i); // "goodbye": "sayonara"
3259+
assert_eq!(indents(lines[5]), 1 * i); // },
3260+
assert_eq!(indents(lines[6]), 0 * i); // ]
3261+
3262+
// Finally, test that the pretty-printed JSON is valid
3263+
from_str(printed).ok().expect("Pretty-printed JSON is invalid!");
3264+
}
3265+
}
3266+
32003267
#[test]
32013268
fn test_hashmap_with_numeric_key_can_handle_double_quote_delimited_key() {
32023269
use std::collections::HashMap;

0 commit comments

Comments
 (0)