]>
Commit | Line | Data |
---|---|---|
f20569fa XL |
1 | //! Enables base64'd output anywhere you might use a `Display` implementation, like a format string. |
2 | //! | |
3 | //! ``` | |
4 | //! use base64::display::Base64Display; | |
5 | //! | |
6 | //! let data = vec![0x0, 0x1, 0x2, 0x3]; | |
7 | //! let wrapper = Base64Display::with_config(&data, base64::STANDARD); | |
8 | //! | |
9 | //! assert_eq!("base64: AAECAw==", format!("base64: {}", wrapper)); | |
10 | //! ``` | |
11 | ||
12 | use super::chunked_encoder::ChunkedEncoder; | |
13 | use super::Config; | |
14 | use core::fmt::{Display, Formatter}; | |
15 | use core::{fmt, str}; | |
16 | ||
17 | /// A convenience wrapper for base64'ing bytes into a format string without heap allocation. | |
18 | pub struct Base64Display<'a> { | |
19 | bytes: &'a [u8], | |
20 | chunked_encoder: ChunkedEncoder, | |
21 | } | |
22 | ||
23 | impl<'a> Base64Display<'a> { | |
24 | /// Create a `Base64Display` with the provided config. | |
25 | pub fn with_config(bytes: &[u8], config: Config) -> Base64Display { | |
26 | Base64Display { | |
27 | bytes, | |
28 | chunked_encoder: ChunkedEncoder::new(config), | |
29 | } | |
30 | } | |
31 | } | |
32 | ||
33 | impl<'a> Display for Base64Display<'a> { | |
34 | fn fmt(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> { | |
35 | let mut sink = FormatterSink { f: formatter }; | |
36 | self.chunked_encoder.encode(self.bytes, &mut sink) | |
37 | } | |
38 | } | |
39 | ||
40 | struct FormatterSink<'a, 'b: 'a> { | |
41 | f: &'a mut Formatter<'b>, | |
42 | } | |
43 | ||
44 | impl<'a, 'b: 'a> super::chunked_encoder::Sink for FormatterSink<'a, 'b> { | |
45 | type Error = fmt::Error; | |
46 | ||
47 | fn write_encoded_bytes(&mut self, encoded: &[u8]) -> Result<(), Self::Error> { | |
48 | // Avoid unsafe. If max performance is needed, write your own display wrapper that uses | |
49 | // unsafe here to gain about 10-15%. | |
50 | self.f | |
51 | .write_str(str::from_utf8(encoded).expect("base64 data was not utf8")) | |
52 | } | |
53 | } | |
54 | ||
55 | #[cfg(test)] | |
56 | mod tests { | |
57 | use super::super::chunked_encoder::tests::{ | |
58 | chunked_encode_matches_normal_encode_random, SinkTestHelper, | |
59 | }; | |
60 | use super::super::*; | |
61 | use super::*; | |
62 | ||
63 | #[test] | |
64 | fn basic_display() { | |
65 | assert_eq!( | |
66 | "~$Zm9vYmFy#*", | |
67 | format!("~${}#*", Base64Display::with_config(b"foobar", STANDARD)) | |
68 | ); | |
69 | assert_eq!( | |
70 | "~$Zm9vYmFyZg==#*", | |
71 | format!("~${}#*", Base64Display::with_config(b"foobarf", STANDARD)) | |
72 | ); | |
73 | } | |
74 | ||
75 | #[test] | |
76 | fn display_encode_matches_normal_encode() { | |
77 | let helper = DisplaySinkTestHelper; | |
78 | chunked_encode_matches_normal_encode_random(&helper); | |
79 | } | |
80 | ||
81 | struct DisplaySinkTestHelper; | |
82 | ||
83 | impl SinkTestHelper for DisplaySinkTestHelper { | |
84 | fn encode_to_string(&self, config: Config, bytes: &[u8]) -> String { | |
85 | format!("{}", Base64Display::with_config(bytes, config)) | |
86 | } | |
87 | } | |
88 | } |