@@ -63,22 +63,29 @@ impl Writer {
63
63
self . 0 . len ( )
64
64
}
65
65
66
- /// Insert the length of a data slice before the slice start
67
- pub fn insert_length ( & mut self , slice_start : usize , length_adjust : usize ) -> Result < ( ) , :: std:: io:: Error > {
66
+ /// Write the data with a varint length prefix.
67
+ /// Use length_adjust to add to the length for special cases, such as writing an Option.
68
+ pub fn write_all_with_length < T : Writeable > ( & mut self , data : & T , length_adjust : usize ) -> Result < ( ) , :: std:: io:: Error > {
69
+ // Most common case is a single byte length prefix, so leave a space for that
70
+ self . 0 . push ( 0 ) ;
71
+ let start = self . len ( ) ;
72
+ data. write ( self ) . expect ( "No in-memory data may fail to serialize" ) ;
73
+ self . insert_length ( start, length_adjust)
74
+ }
75
+
76
+ fn insert_length ( & mut self , slice_start : usize , length_adjust : usize ) -> Result < ( ) , :: std:: io:: Error > {
68
77
let slice_end = self . len ( ) ;
69
78
let length = slice_end - slice_start + length_adjust;
70
- // Write the length after the slice, to check how many bytes
71
- BigSize ( length as u64 ) . write ( self ) ?;
72
- let len_end = self . len ( ) ;
73
- let len_len = len_end - slice_end;
74
- self . 0 . resize ( slice_end, 0 ) ;
75
- // Shift the slice to make space for the length
76
- for _ in 0 .. len_len {
79
+ let big_size = BigSize ( length as u64 ) ;
80
+ let len_len = big_size. expected_length ( ) ;
81
+ // At this point we have a placeholder for a varint of length 1 just before the start of data
82
+ // Shift the slice to make space for the length. If len_len is 1, no shift is needed.
83
+ for _ in 1 ..len_len {
77
84
self . 0 . insert ( slice_start, 0 ) ;
78
85
}
79
86
let mut cursor = Cursor :: new ( & mut self . 0 ) ;
80
- cursor. set_position ( slice_start as u64 ) ;
81
- // Write the length again at the right spot
87
+ cursor. set_position ( ( slice_start - 1 ) as u64 ) ;
88
+ // Write the length in the space we created before the start of data
82
89
BigSize ( length as u64 ) . write_write ( & mut cursor)
83
90
}
84
91
}
@@ -264,6 +271,15 @@ impl BigSize {
264
271
} ,
265
272
}
266
273
}
274
+
275
+ pub fn expected_length ( & self ) -> usize {
276
+ match self . 0 {
277
+ 0 ...0xFC => 1 ,
278
+ 0xFD ...0xFFFF => 3 ,
279
+ 0x10000 ...0xFFFFFFFF => 5 ,
280
+ _ => 9 ,
281
+ }
282
+ }
267
283
}
268
284
269
285
impl Writeable for BigSize {
@@ -634,9 +650,7 @@ impl<T: Writeable> Writeable for Option<T> {
634
650
match * self {
635
651
None => 0u8 . write ( w) ?,
636
652
Some ( ref data) => {
637
- let start = w. len ( ) ;
638
- data. write ( w) . expect ( "No in-memory data may fail to serialize" ) ;
639
- w. insert_length ( start, 1 ) ?;
653
+ w. write_all_with_length ( data, 1 ) ?;
640
654
}
641
655
}
642
656
Ok ( ( ) )
@@ -756,3 +770,56 @@ impl<A: Writeable, B: Writeable> Writeable for (A, B) {
756
770
self . 1 . write ( w)
757
771
}
758
772
}
773
+
774
+ #[ cfg( test) ]
775
+ mod tests {
776
+ use std:: io:: Cursor ;
777
+ use util:: ser:: * ;
778
+
779
+ #[ test]
780
+ fn big_size ( ) {
781
+ for i in vec ! [ 0 , 0xfc , 0xfd , 0xffff , 0x10000 , 0xFFFFFFFF , 0xFFFFFFFFF ] {
782
+ let mut writer = Writer :: new ( ) ;
783
+ let size = BigSize ( i) ;
784
+ size. write ( & mut writer) . unwrap ( ) ;
785
+ assert_eq ! ( writer. len( ) , size. expected_length( ) ) ;
786
+ let read_size = BigSize :: read ( & mut Cursor :: new ( writer. 0 ) ) . unwrap ( ) ;
787
+ assert_eq ! ( read_size. 0 , size. 0 ) ;
788
+ }
789
+ }
790
+
791
+ #[ test]
792
+ fn length_prefix_zero ( ) {
793
+ impl_array ! ( 0 ) ;
794
+ let mut writer = Writer :: new ( ) ;
795
+ writer. write_all_with_length ( & [ ] , 0 ) . unwrap ( ) ;
796
+ // Writing a zero-length length-prefixed item should result in just one zero byte
797
+ assert_eq ! ( writer. 0 , vec![ 0 ] ) ;
798
+ }
799
+
800
+ #[ test]
801
+ fn length_prefix_one ( ) {
802
+ impl_array ! ( 1 ) ;
803
+ let mut writer = Writer :: new ( ) ;
804
+ writer. write_all_with_length ( & [ 0x11u8 ] , 0 ) . unwrap ( ) ;
805
+ assert_eq ! ( writer. 0 , vec![ 1 , 0x11 ] ) ;
806
+ }
807
+
808
+ #[ test]
809
+ fn length_prefix ( ) {
810
+ for size in vec ! [ 3 , 0xfc , 0xfd , 0xffff , 0x10000 ] {
811
+ let mut writer = Writer :: new ( ) ;
812
+ let mut data = Vec :: new ( ) ;
813
+ // A Vec serializes its own 2 bytes length, so adjust this
814
+ data. resize ( size-3 , 0x11u8 ) ;
815
+ // Writing an Option is convenient for round-trip checking of length-prefixed writes
816
+ Some ( data. clone ( ) ) . write ( & mut writer) . unwrap ( ) ;
817
+ let mut reader = Cursor :: new ( & writer. 0 ) ;
818
+ let read_data: Option < Vec < u8 > > = Readable :: read ( & mut reader) . unwrap ( ) ;
819
+ assert_eq ! ( data, read_data. unwrap( ) ) ;
820
+ // Ensure everything was consumed
821
+ assert_eq ! ( reader. position( ) as usize , writer. len( ) ) ;
822
+ println ! ( "{}" , writer. len( ) )
823
+ }
824
+ }
825
+ }
0 commit comments