11use std:: io:: { Read , Result , Write } ;
22
3- const CHUNK_SIZE : usize = 1024 ;
4- pub struct Chunked < R : Read > {
3+ /// A reader for [HTTP Chunked transfer encoding]
4+ ///
5+ /// [HTTP Chunked transfer encoding]: <https://en.wikipedia.org/wiki/Chunked_transfer_encoding>
6+ pub struct Chunked < R : Read , const CHUNK_SIZE : usize = 1024 > {
57 reader : R ,
68 chunk : Vec < u8 > ,
79 offset : usize ,
8- finish : bool ,
910}
1011
1112impl < R : Read > Chunked < R > {
13+ /// Creates a `Chunked` struct with the default size.
14+ pub fn with_default_size ( reader : R ) -> Chunked < R > {
15+ Self :: new ( reader)
16+ }
17+ }
18+
19+ impl < R : Read , const CHUNK_SIZE : usize > Chunked < R , CHUNK_SIZE > {
20+
21+ /// The size of the chunks
22+ pub const CHUNK_SIZE : usize = CHUNK_SIZE ;
23+
1224 pub fn new ( reader : R ) -> Self {
13- Self {
25+ Chunked {
1426 reader,
1527 chunk : Vec :: with_capacity ( CHUNK_SIZE + 8 ) ,
1628 offset : 0 ,
17- finish : false ,
1829 }
1930 }
2031 fn next_chunk ( & mut self ) -> Result < bool > {
21- if self . finish {
22- return Ok ( false ) ;
23- }
2432 self . chunk . clear ( ) ;
2533 self . offset = 0 ;
2634
2735 let mut tmpbuf: [ u8 ; CHUNK_SIZE ] = [ 0 ; CHUNK_SIZE ] ;
2836 let n = self . reader . read ( & mut tmpbuf) ?;
2937 if n == 0 {
30- self . finish = true ;
38+ return Ok ( false )
3139 }
3240 self . chunk . write_all ( format ! ( "{n:X}\r \n " ) . as_bytes ( ) ) ?;
3341 self . chunk . write_all ( & tmpbuf[ 0 ..n] ) ?;
3442 self . chunk . write_all ( b"\r \n " ) ?;
3543 Ok ( true )
3644 }
45+
46+ /// Returns the current chunk
47+ ///
48+ /// # NOTE
49+ /// This method returns the whole chunk, even the parts alredy
50+ /// read. If you want to know the remaining portion of the chunk
51+ /// that hasn't been polled, see [offset](Self::offset)
52+ pub fn current_chunk ( & self ) -> & [ u8 ] { & self . chunk }
53+
54+ /// Returns the current offset. This is: The offset to the
55+ /// part of the current chunk that hasn't been read yet
56+ pub fn offset ( & self ) -> usize { self . offset }
3757}
3858
39- impl < R : Read > Read for Chunked < R > {
59+ impl < R : Read , const CHUNK_SIZE : usize > Read for Chunked < R , CHUNK_SIZE > {
4060 fn read ( & mut self , buf : & mut [ u8 ] ) -> std:: io:: Result < usize > {
4161 if self . offset >= self . chunk . len ( ) && !self . next_chunk ( ) ? {
4262 return Ok ( 0 ) ;
@@ -51,3 +71,48 @@ impl<R: Read> Read for Chunked<R> {
5171 Ok ( n)
5272 }
5373}
74+
75+ impl < R : Read + Default > Default for Chunked < R > {
76+ fn default ( ) -> Self {
77+ Self :: new ( R :: default ( ) )
78+ }
79+ }
80+
81+ #[ cfg( test) ]
82+ mod test {
83+ pub use super :: * ;
84+
85+ const SIZE : usize = 1024 ;
86+
87+ fn test_chunks ( input : & str ) {
88+ let mut chunked = Chunked :: < _ , SIZE > :: new ( input. as_bytes ( ) ) ;
89+ let mut out = Vec :: new ( ) ;
90+
91+ chunked. read_to_end ( & mut out) . unwrap ( ) ;
92+
93+ let mut expected = Vec :: new ( ) ;
94+ for chunk in input. as_bytes ( ) . chunks ( SIZE ) {
95+ expected. extend_from_slice ( format ! ( "{:X}\r \n " , chunk. len( ) ) . as_bytes ( ) ) ;
96+ expected. extend_from_slice ( chunk) ;
97+ expected. extend_from_slice ( b"\r \n " ) ;
98+ }
99+ assert_eq ! ( out, expected) ;
100+ }
101+
102+ #[ test]
103+ fn small ( ) {
104+ test_chunks ( "abcdefg" ) ;
105+ test_chunks ( & "0" . repeat ( SIZE - 50 ) ) ;
106+ }
107+
108+ #[ test]
109+ fn exact_chunks ( ) {
110+ test_chunks ( & "a" . repeat ( SIZE ) ) ;
111+ test_chunks ( & "a" . repeat ( SIZE * 2 ) ) ;
112+ }
113+
114+ #[ test]
115+ fn with_remaining ( ) {
116+ test_chunks ( & "a" . repeat ( SIZE + 200 ) ) ;
117+ }
118+ }
0 commit comments