/rust/registry/src/index.crates.io-6f17d22bba15001f/base64-0.22.1/src/display.rs
Line | Count | Source (jump to first uncovered line) |
1 | | //! Enables base64'd output anywhere you might use a `Display` implementation, like a format string. |
2 | | //! |
3 | | //! ``` |
4 | | //! use base64::{display::Base64Display, engine::general_purpose::STANDARD}; |
5 | | //! |
6 | | //! let data = vec![0x0, 0x1, 0x2, 0x3]; |
7 | | //! let wrapper = Base64Display::new(&data, &STANDARD); |
8 | | //! |
9 | | //! assert_eq!("base64: AAECAw==", format!("base64: {}", wrapper)); |
10 | | //! ``` |
11 | | |
12 | | use super::chunked_encoder::ChunkedEncoder; |
13 | | use crate::engine::Engine; |
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, 'e, E: Engine> { |
19 | | bytes: &'a [u8], |
20 | | chunked_encoder: ChunkedEncoder<'e, E>, |
21 | | } |
22 | | |
23 | | impl<'a, 'e, E: Engine> Base64Display<'a, 'e, E> { |
24 | | /// Create a `Base64Display` with the provided engine. |
25 | 0 | pub fn new(bytes: &'a [u8], engine: &'e E) -> Base64Display<'a, 'e, E> { |
26 | 0 | Base64Display { |
27 | 0 | bytes, |
28 | 0 | chunked_encoder: ChunkedEncoder::new(engine), |
29 | 0 | } |
30 | 0 | } |
31 | | } |
32 | | |
33 | | impl<'a, 'e, E: Engine> Display for Base64Display<'a, 'e, E> { |
34 | 0 | fn fmt(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> { |
35 | 0 | let mut sink = FormatterSink { f: formatter }; |
36 | 0 | self.chunked_encoder.encode(self.bytes, &mut sink) |
37 | 0 | } |
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 | 0 | fn write_encoded_bytes(&mut self, encoded: &[u8]) -> Result<(), Self::Error> { |
48 | 0 | // Avoid unsafe. If max performance is needed, write your own display wrapper that uses |
49 | 0 | // unsafe here to gain about 10-15%. |
50 | 0 | self.f |
51 | 0 | .write_str(str::from_utf8(encoded).expect("base64 data was not utf8")) |
52 | 0 | } |
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::*; |
61 | | use crate::engine::general_purpose::STANDARD; |
62 | | |
63 | | #[test] |
64 | | fn basic_display() { |
65 | | assert_eq!( |
66 | | "~$Zm9vYmFy#*", |
67 | | format!("~${}#*", Base64Display::new(b"foobar", &STANDARD)) |
68 | | ); |
69 | | assert_eq!( |
70 | | "~$Zm9vYmFyZg==#*", |
71 | | format!("~${}#*", Base64Display::new(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<E: Engine>(&self, engine: &E, bytes: &[u8]) -> String { |
85 | | format!("{}", Base64Display::new(bytes, engine)) |
86 | | } |
87 | | } |
88 | | } |