@@ -25,27 +25,24 @@ const MIN_ENCODE_CHUNK_SIZE: usize = 3;
2525/// use std::io::Write;
2626///
2727/// // use a vec as the simplest possible `Write` -- in real code this is probably a file, etc.
28- /// let mut wrapped_writer = Vec::new();
29- /// {
30- /// let mut enc = base64::write::EncoderWriter::new(
31- /// &mut wrapped_writer, base64::STANDARD);
28+ /// let mut enc = base64::write::EncoderWriter::new(Vec::new(), base64::STANDARD);
3229///
33- /// // handle errors as you normally would
34- /// enc.write_all(b"asdf").unwrap();
35- /// // could leave this out to be called by Drop, if you don't care
36- /// // about handling errors
37- /// enc.finish().unwrap();
30+ /// // handle errors as you normally would
31+ /// enc.write_all(b"asdf").unwrap();
3832///
39- /// }
33+ /// // could leave this out to be called by Drop, if you don't care
34+ /// // about handling errors or getting the delegate writer back
35+ /// let delegate = enc.finish().unwrap();
4036///
4137/// // base64 was written to the writer
42- /// assert_eq!(b"YXNkZg==", &wrapped_writer [..]);
38+ /// assert_eq!(b"YXNkZg==", &delegate [..]);
4339///
4440/// ```
4541///
4642/// # Panics
4743///
48- /// Calling `write()` after `finish()` is invalid and will panic.
44+ /// Calling `write()` (or related methods) or `finish()` after `finish()` has completed without
45+ /// error is invalid and will panic.
4946///
5047/// # Errors
5148///
@@ -56,10 +53,12 @@ const MIN_ENCODE_CHUNK_SIZE: usize = 3;
5653///
5754/// It has some minor performance loss compared to encoding slices (a couple percent).
5855/// It does not do any heap allocation.
59- pub struct EncoderWriter < ' a , W : ' a + Write > {
56+ pub struct EncoderWriter < W : Write > {
6057 config : Config ,
61- /// Where encoded data is written to
62- w : & ' a mut W ,
58+ /// Where encoded data is written to. It's an Option as it's None immediately before Drop is
59+ /// called so that finish() can return the underlying writer. None implies that finish() has
60+ /// been called successfully.
61+ delegate : Option < W > ,
6362 /// Holds a partial chunk, if any, after the last `write()`, so that we may then fill the chunk
6463 /// with the next `write()`, encode it, then proceed with the rest of the input normally.
6564 extra_input : [ u8 ; MIN_ENCODE_CHUNK_SIZE ] ,
@@ -70,13 +69,11 @@ pub struct EncoderWriter<'a, W: 'a + Write> {
7069 output : [ u8 ; BUF_SIZE ] ,
7170 /// How much of `output` is occupied with encoded data that couldn't be written last time
7271 output_occupied_len : usize ,
73- /// True iff padding / partial last chunk has been written.
74- finished : bool ,
7572 /// panic safety: don't write again in destructor if writer panicked while we were writing to it
7673 panicked : bool ,
7774}
7875
79- impl < ' a , W : Write > fmt:: Debug for EncoderWriter < ' a , W > {
76+ impl < W : Write > fmt:: Debug for EncoderWriter < W > {
8077 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
8178 write ! (
8279 f,
@@ -89,38 +86,58 @@ impl<'a, W: Write> fmt::Debug for EncoderWriter<'a, W> {
8986 }
9087}
9188
92- impl < ' a , W : Write > EncoderWriter < ' a , W > {
89+ impl < W : Write > EncoderWriter < W > {
9390 /// Create a new encoder that will write to the provided delegate writer `w`.
94- pub fn new ( w : & ' a mut W , config : Config ) -> EncoderWriter < ' a , W > {
91+ pub fn new ( w : W , config : Config ) -> EncoderWriter < W > {
9592 EncoderWriter {
9693 config,
97- w ,
94+ delegate : Some ( w ) ,
9895 extra_input : [ 0u8 ; MIN_ENCODE_CHUNK_SIZE ] ,
9996 extra_input_occupied_len : 0 ,
10097 output : [ 0u8 ; BUF_SIZE ] ,
10198 output_occupied_len : 0 ,
102- finished : false ,
10399 panicked : false ,
104100 }
105101 }
106102
107103 /// Encode all remaining buffered data and write it, including any trailing incomplete input
108104 /// triples and associated padding.
109105 ///
110- /// Once this succeeds, no further writes can be performed, as that would produce invalid
111- /// base64.
106+ /// Once this succeeds, no further writes or calls to this method are allowed.
112107 ///
113- /// This may write to the delegate writer multiple times if the delegate writer does not accept all input provided
114- /// to its `write` each invocation.
108+ /// This may write to the delegate writer multiple times if the delegate writer does not accept
109+ /// all input provided to its `write` each invocation.
110+ ///
111+ /// If you don't care about error handling, it is not necessary to call this function, as the
112+ /// equivalent finalization is done by the Drop impl.
113+ ///
114+ /// Returns the writer that this was constructed around.
115115 ///
116116 /// # Errors
117117 ///
118- /// The first error that is not of [`ErrorKind::Interrupted`] will be returned.
119- pub fn finish ( & mut self ) -> Result < ( ) > {
120- if self . finished {
121- return Ok ( ( ) ) ;
118+ /// The first error that is not of `ErrorKind::Interrupted` will be returned.
119+ pub fn finish ( & mut self ) -> Result < W > {
120+ // If we could consume self in finish(), we wouldn't have to worry about this case, but
121+ // finish() is retryable in the face of I/O errors, so we can't consume here.
122+ if self . delegate . is_none ( ) {
123+ panic ! ( "Encoder has already had finish() called" )
122124 } ;
123125
126+ self . write_final_leftovers ( ) ?;
127+
128+ let writer = self . delegate . take ( ) . expect ( "Writer must be present" ) ;
129+
130+ Ok ( writer)
131+ }
132+
133+ /// Write any remaining buffered data to the delegate writer.
134+ fn write_final_leftovers ( & mut self ) -> Result < ( ) > {
135+ if self . delegate . is_none ( ) {
136+ // finish() has already successfully called this, and we are now in drop() with a None
137+ // writer, so just no-op
138+ return Ok ( ( ) ) ;
139+ }
140+
124141 self . write_all_encoded_output ( ) ?;
125142
126143 if self . extra_input_occupied_len > 0 {
@@ -138,7 +155,6 @@ impl<'a, W: Write> EncoderWriter<'a, W> {
138155 self . extra_input_occupied_len = 0 ;
139156 }
140157
141- self . finished = true ;
142158 Ok ( ( ) )
143159 }
144160
@@ -152,7 +168,11 @@ impl<'a, W: Write> EncoderWriter<'a, W> {
152168 /// that no write took place.
153169 fn write_to_delegate ( & mut self , current_output_len : usize ) -> Result < ( ) > {
154170 self . panicked = true ;
155- let res = self . w . write ( & self . output [ ..current_output_len] ) ;
171+ let res = self
172+ . delegate
173+ . as_mut ( )
174+ . expect ( "Writer must be present" )
175+ . write ( & self . output [ ..current_output_len] ) ;
156176 self . panicked = false ;
157177
158178 res. map ( |consumed| {
@@ -197,7 +217,7 @@ impl<'a, W: Write> EncoderWriter<'a, W> {
197217 }
198218}
199219
200- impl < ' a , W : Write > Write for EncoderWriter < ' a , W > {
220+ impl < W : Write > Write for EncoderWriter < W > {
201221 /// Encode input and then write to the delegate writer.
202222 ///
203223 /// Under non-error circumstances, this returns `Ok` with the value being the number of bytes
@@ -215,7 +235,7 @@ impl<'a, W: Write> Write for EncoderWriter<'a, W> {
215235 ///
216236 /// Any errors emitted by the delegate writer are returned.
217237 fn write ( & mut self , input : & [ u8 ] ) -> Result < usize > {
218- if self . finished {
238+ if self . delegate . is_none ( ) {
219239 panic ! ( "Cannot write more after calling finish()" ) ;
220240 }
221241
@@ -341,15 +361,18 @@ impl<'a, W: Write> Write for EncoderWriter<'a, W> {
341361 /// incomplete chunks of input or write padding.
342362 fn flush ( & mut self ) -> Result < ( ) > {
343363 self . write_all_encoded_output ( ) ?;
344- self . w . flush ( )
364+ self . delegate
365+ . as_mut ( )
366+ . expect ( "Writer must be present" )
367+ . flush ( )
345368 }
346369}
347370
348- impl < ' a , W : Write > Drop for EncoderWriter < ' a , W > {
371+ impl < W : Write > Drop for EncoderWriter < W > {
349372 fn drop ( & mut self ) {
350373 if !self . panicked {
351374 // like `BufWriter`, ignore errors during drop
352- let _ = self . finish ( ) ;
375+ let _ = self . write_final_leftovers ( ) ;
353376 }
354377 }
355378}
0 commit comments