Skip to content

Commit c509f79

Browse files
committed
auto merge of #16601 : cybergeek94/rust/master, r=alexcrichton
Previously, `PrettyEncoder` indented a magic constant of 2 spaces per level, which may be fine for most uses but in my use case I would like to allow the user to specify the indent step for the outputted JSON in my program. This is small change that does not break any existing code whatsoever, and does not change the behavior of existing uses. `PrettyEncoder::new()` still uses the default of 2. I couldn't think of any simple tests for this change. The obvious one would be to check the outputted JSON for the correct number of spaces per indent level, but I think that would be more complex than the actual change itself and test little besides correctness and consistency, which can be verified visually. There's already a test for correct parsing of pretty-printed JSON that should still pass with this change.
2 parents f92015f + 1028120 commit c509f79

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)