serde_bytes_repr/
lib.rs

1//! # Serde adapter for (de)serializing bytes to and from specific formats
2//!
3//! Currently these representations is supported:
4//!
5//! - Base64
6//! - Hexidecimal
7//!
8//! Human readable formats tend not to include a universally agreed way to represent arbitrary binary
9//! data, which means those serde libraries can end up using a representation for serde's "bytes" type
10//! which isn't ideal for all uses. This library gives you the option to choose a different
11//! representation than the default for libraries like `serde_json`, `toml` and `serde_yaml`.
12//!
13//! ## How to make sure that your datatype is interpreted as bytes?
14//!
15//! Without specialization, Rust forces Serde to treat &[u8] just like any other
16//! slice and Vec<u8> just like any other vector. To enable specialized handling
17//! of `&[u8]` can use the [serde_bytes](https://docs.rs/serde_bytes/0.11.5/serde_bytes/index.html) crate.
18//!
19//! You'll se this in use in the examples below:
20//!
21//! ## Serialization
22//!
23//! ```rust
24//! use serde::{Deserialize, Serialize};
25//! use serde_bytes_repr::ByteFmtSerializer;
26//! # fn main() {
27//!     #[derive(Serialize, Deserialize)]
28//!     struct Demo {
29//!         #[serde(with = "serde_bytes")]
30//!         bytes: Vec<u8>,
31//!     }
32//!     let bytes = b"testing".to_vec();
33//!     let demo = Demo { bytes };
34//!
35//!     let mut out = vec![];
36//!     let mut ser = serde_json::Serializer::new(&mut out);
37//!     let base64_config = base64::engine::GeneralPurposeConfig::new();
38//!     let ser = ByteFmtSerializer::base64(&mut ser,  base64::alphabet::URL_SAFE, base64_config);
39//!     demo.serialize(ser).unwrap();
40//!
41//!     let serialized = String::from_utf8(out).unwrap();
42//!     assert_eq!(r#"{"bytes":"dGVzdGluZw=="}"#, serialized.as_str());
43//! # }
44//! ```
45//!
46//! ## Deserialization
47//!
48//! ```rust
49//! use serde::{Deserialize, Serialize};
50//! use serde_bytes_repr::{ByteFmtDeserializer, ByteFmtSerializer};
51//! # fn main() {
52//!     #[derive(Serialize, Deserialize)]
53//!     struct Demo {
54//!         #[serde(with = "serde_bytes")]
55//!         bytes: Vec<u8>,
56//!     }
57//!
58//!     let json = br#"{"bytes":"dGVzdGluZw=="}"#;
59//!     let mut json_de = serde_json::Deserializer::from_slice(json);
60//!     let base64_config = base64::engine::GeneralPurposeConfig::new();
61//!     let bytefmt_json_de = ByteFmtDeserializer::new_base64(&mut json_de, base64::alphabet::URL_SAFE, base64_config);
62//!     let demo: Demo = Demo::deserialize(bytefmt_json_de).unwrap();
63//!
64//!     let deserialized = String::from_utf8(demo.bytes).unwrap();
65//!     assert_eq!("testing", deserialized.as_str());
66//! # }
67//! ```
68
69use base64::{alphabet::Alphabet, engine::GeneralPurposeConfig, Engine};
70
71mod deserializer;
72mod serializer;
73
74#[derive(Clone)]
75enum ByteFormat {
76    Base64(Alphabet, GeneralPurposeConfig),
77    Hex,
78}
79
80/// Serializer-adapter which encodes bytes to using the specified encoding. The format is
81/// serialized to the data formats string representation.
82pub struct ByteFmtSerializer<S> {
83    inner: S,
84    encode_kind: ByteFormat,
85}
86impl<S> ByteFmtSerializer<S> {
87    /// Crates an adapter which serializes to and from a Base64 representation.
88    /// Provide a configuration from the `base64` crate specifying the specifics
89    /// on how you want the bytes encoded.
90    pub fn base64(ser: S, alphabet: Alphabet, config: GeneralPurposeConfig) -> Self {
91        Self {
92            inner: ser,
93            encode_kind: ByteFormat::Base64(alphabet, config),
94        }
95    }
96
97    /// Creates an adapter which serializes to a HEX representation.
98    pub fn hex(ser: S) -> Self {
99        Self {
100            inner: ser,
101            encode_kind: ByteFormat::Hex,
102        }
103    }
104
105    fn encode(&self, v: &[u8]) -> String {
106        match self.encode_kind {
107            ByteFormat::Base64(ref alphabet, config) => {
108                base64::engine::GeneralPurpose::new(alphabet, config).encode(v)
109            }
110            ByteFormat::Hex => hex::encode(v),
111        }
112    }
113}
114
115/// Deserializer-adapter which decodes bytes from a specified format.
116pub struct ByteFmtDeserializer<D> {
117    pub inner: D,
118    fmt: ByteFormat,
119}
120
121impl<D> ByteFmtDeserializer<D> {
122    /// Crates an adapter which deserializes from a Base64 representation. Provide a
123    /// configuration from the `base64` crate specifying the specifics on how you want the bytes
124    /// encoded.
125    ///
126    pub fn new_base64(deserializer: D, alphabet: Alphabet, config: GeneralPurposeConfig) -> Self {
127        ByteFmtDeserializer {
128            inner: deserializer,
129            fmt: ByteFormat::Base64(alphabet, config),
130        }
131    }
132
133    /// Creates an adapter which deserializes from a HEX representation.
134    pub fn new_hex(deserializer: D) -> Self {
135        ByteFmtDeserializer {
136            inner: deserializer,
137            fmt: ByteFormat::Hex,
138        }
139    }
140}