[−][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.
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 |