encoder_string_writer.rs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. use super::encoder::EncoderWriter;
  2. use crate::Config;
  3. use std::io;
  4. use std::io::Write;
  5. /// A `Write` implementation that base64-encodes data using the provided config and accumulates the
  6. /// resulting base64 in memory, which is then exposed as a String via `into_inner()`.
  7. ///
  8. /// # Examples
  9. ///
  10. /// Buffer base64 in a new String:
  11. ///
  12. /// ```
  13. /// use std::io::Write;
  14. ///
  15. /// let mut enc = base64::write::EncoderStringWriter::new(base64::STANDARD);
  16. ///
  17. /// enc.write_all(b"asdf").unwrap();
  18. ///
  19. /// // get the resulting String
  20. /// let b64_string = enc.into_inner();
  21. ///
  22. /// assert_eq!("YXNkZg==", &b64_string);
  23. /// ```
  24. ///
  25. /// Or, append to an existing String:
  26. ///
  27. /// ```
  28. /// use std::io::Write;
  29. ///
  30. /// let mut buf = String::from("base64: ");
  31. ///
  32. /// let mut enc = base64::write::EncoderStringWriter::from(&mut buf, base64::STANDARD);
  33. ///
  34. /// enc.write_all(b"asdf").unwrap();
  35. ///
  36. /// // release the &mut reference on buf
  37. /// let _ = enc.into_inner();
  38. ///
  39. /// assert_eq!("base64: YXNkZg==", &buf);
  40. /// ```
  41. ///
  42. /// # Panics
  43. ///
  44. /// Calling `write()` (or related methods) or `finish()` after `finish()` has completed without
  45. /// error is invalid and will panic.
  46. ///
  47. /// # Performance
  48. ///
  49. /// Because it has to validate that the base64 is UTF-8, it is about 80% as fast as writing plain
  50. /// bytes to a `io::Write`.
  51. pub struct EncoderStringWriter<S: StrConsumer> {
  52. encoder: EncoderWriter<Utf8SingleCodeUnitWriter<S>>,
  53. }
  54. impl<S: StrConsumer> EncoderStringWriter<S> {
  55. /// Create a EncoderStringWriter that will append to the provided `StrConsumer`.
  56. pub fn from(str_consumer: S, config: Config) -> Self {
  57. EncoderStringWriter {
  58. encoder: EncoderWriter::new(Utf8SingleCodeUnitWriter { str_consumer }, config),
  59. }
  60. }
  61. /// Encode all remaining buffered data, including any trailing incomplete input triples and
  62. /// associated padding.
  63. ///
  64. /// Once this succeeds, no further writes or calls to this method are allowed.
  65. ///
  66. /// Returns the base64-encoded form of the accumulated written data.
  67. pub fn into_inner(mut self) -> S {
  68. self.encoder
  69. .finish()
  70. .expect("Writing to a Vec<u8> should never fail")
  71. .str_consumer
  72. }
  73. }
  74. impl EncoderStringWriter<String> {
  75. /// Create a EncoderStringWriter that will encode into a new String with the provided config.
  76. pub fn new(config: Config) -> Self {
  77. EncoderStringWriter::from(String::new(), config)
  78. }
  79. }
  80. impl<S: StrConsumer> Write for EncoderStringWriter<S> {
  81. fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
  82. self.encoder.write(buf)
  83. }
  84. fn flush(&mut self) -> io::Result<()> {
  85. self.encoder.flush()
  86. }
  87. }
  88. /// An abstraction around consuming `str`s produced by base64 encoding.
  89. pub trait StrConsumer {
  90. /// Consume the base64 encoded data in `buf`
  91. fn consume(&mut self, buf: &str);
  92. }
  93. /// As for io::Write, `StrConsumer` is implemented automatically for `&mut S`.
  94. impl<S: StrConsumer + ?Sized> StrConsumer for &mut S {
  95. fn consume(&mut self, buf: &str) {
  96. (**self).consume(buf)
  97. }
  98. }
  99. /// Pushes the str onto the end of the String
  100. impl StrConsumer for String {
  101. fn consume(&mut self, buf: &str) {
  102. self.push_str(buf)
  103. }
  104. }
  105. /// A `Write` that only can handle bytes that are valid single-byte UTF-8 code units.
  106. ///
  107. /// This is safe because we only use it when writing base64, which is always valid UTF-8.
  108. struct Utf8SingleCodeUnitWriter<S: StrConsumer> {
  109. str_consumer: S,
  110. }
  111. impl<S: StrConsumer> io::Write for Utf8SingleCodeUnitWriter<S> {
  112. fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
  113. // Because we expect all input to be valid utf-8 individual bytes, we can encode any buffer
  114. // length
  115. let s = std::str::from_utf8(buf).expect("Input must be valid UTF-8");
  116. self.str_consumer.consume(s);
  117. Ok(buf.len())
  118. }
  119. fn flush(&mut self) -> io::Result<()> {
  120. // no op
  121. Ok(())
  122. }
  123. }
  124. #[cfg(test)]
  125. mod tests {
  126. use crate::encode_config_buf;
  127. use crate::tests::random_config;
  128. use crate::write::encoder_string_writer::EncoderStringWriter;
  129. use rand::Rng;
  130. use std::io::Write;
  131. #[test]
  132. fn every_possible_split_of_input() {
  133. let mut rng = rand::thread_rng();
  134. let mut orig_data = Vec::<u8>::new();
  135. let mut normal_encoded = String::new();
  136. let size = 5_000;
  137. for i in 0..size {
  138. orig_data.clear();
  139. normal_encoded.clear();
  140. for _ in 0..size {
  141. orig_data.push(rng.gen());
  142. }
  143. let config = random_config(&mut rng);
  144. encode_config_buf(&orig_data, config, &mut normal_encoded);
  145. let mut stream_encoder = EncoderStringWriter::new(config);
  146. // Write the first i bytes, then the rest
  147. stream_encoder.write_all(&orig_data[0..i]).unwrap();
  148. stream_encoder.write_all(&orig_data[i..]).unwrap();
  149. let stream_encoded = stream_encoder.into_inner();
  150. assert_eq!(normal_encoded, stream_encoded);
  151. }
  152. }
  153. }