@@ -595,13 +595,23 @@ impl<'a> ::Encoder<io::IoError> for Encoder<'a> {
595595/// compact data
596596pub struct PrettyEncoder < ' a > {
597597 writer : & ' a mut io:: Writer ,
598+ curr_indent : uint ,
598599 indent : uint ,
599600}
600601
601602impl < ' 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 , 4 u) {
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