[−][src]Crate hex_buffer_serde
Serializing byte buffers as hex strings with serde
.
Problem
Sometimes, you need to serialize a byte buffer (say, a newtype around [u8; 32]
or Vec<u8>
)
as a hex string. The problem is, the newtype in question can be defined in another crate
(for example, cryptographic types from sodiumoxide
), so you can't implement Serialize
/
Deserialize
for the type due to Rust orphaning rules. (Or maybe Serialize
/ Deserialize
are implemented, but not in the desirable way.)
Solution
The core of this crate is the Hex
trait. It provides methods serialize
and deserialize
, which signatures match the ones expected by serde
. These methods
use the other two required methods of the trait. As all trait methods have no self
argument,
the trait can be implemented for external types; the implementor may be an empty enum
designated specifically for this purpose. The implementor can then be used
for (de)serialization with the help of the #[serde(with)]
attribute.
Crate Features
std
(enabled by default): Enables types from the Rust standard library. Switching this feature off can be used for constrained environments, such as WASM. Note that the crate still requires an allocator (that is, thealloc
crate) even if thestd
feature is disabled.
Examples
// Assume this type is defined in an external crate. pub struct Buffer([u8; 8]); impl Buffer { pub fn from_slice(slice: &[u8]) -> Option<Self> { // snip } } impl AsRef<[u8]> for Buffer { fn as_ref(&self) -> &[u8] { &self.0 } } // We define in our crate: use hex_buffer_serde::Hex; use serde_derive::*; enum BufferHex {} // a single-purpose type for use in `#[serde(with)]` impl Hex<Buffer> for BufferHex { fn create_bytes(buffer: &Buffer) -> Cow<[u8]> { buffer.as_ref().into() } fn from_bytes(bytes: &[u8]) -> Result<Buffer, String> { Buffer::from_slice(bytes).ok_or_else(|| "invalid byte length".to_owned()) } } #[derive(Serialize, Deserialize)] pub struct Example { #[serde(with = "BufferHex")] buffer: Buffer, // other fields... }
Use with internal types
The crate could still be useful if you have control over the serialized buffer type.
Hex<T>
has a blanket implementation for types T
satisfying certain constraints:
AsRef<[u8]>
and TryFrom<&[u8]>
. If these constraints are satisfied, you can
use HexForm::<T>
in #[serde(with)]
:
// It is necessary for `Hex` to be in scope in order // for `serde`-generated code to use its `serialize` / `deserialize` methods. use hex_buffer_serde::{Hex, HexForm}; use core::{array::TryFromSliceError, convert::TryFrom}; pub struct OurBuffer([u8; 8]); impl TryFrom<&[u8]> for OurBuffer { type Error = TryFromSliceError; fn try_from(slice: &[u8]) -> Result<Self, Self::Error> { // snip } } impl AsRef<[u8]> for OurBuffer { fn as_ref(&self) -> &[u8] { &self.0 } } #[derive(Serialize, Deserialize)] pub struct Example { #[serde(with = "HexForm::<OurBuffer>")] buffer: OurBuffer, // other fields... }
Structs
HexForm | A dummy container for use inside |
Traits
Hex | Provides hex-encoded (de)serialization for |