byte_wrapper/lib.rs
1// Copyright (c) The byte-wrapper Contributors
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! Newtype wrappers for byte arrays and vectors with hex and base64
5//! formatting.
6//!
7//! This crate provides wrapper types that display byte data in
8//! human-readable encodings. [`HexArray<N>`] encodes fixed-length byte
9//! arrays as hex strings, and [`Base64Vec`] encodes variable-length
10//! byte vectors as base64 strings.
11//!
12//! With the `serde` feature, both types implement `Serialize` and
13//! `Deserialize`, encoding as human-readable strings (hex or base64) in text
14//! formats like JSON, and as efficient raw bytes in binary formats like [CBOR].
15//! You do not have to use the newtypes in your own type definitions; you can
16//! refer to them via `#[serde(with = "...")]` instead.
17//!
18//! With the `schemars08` feature, both types implement [`JsonSchema`],
19//! including automatic opt-in replacement with
20//! [typify](https://crates.io/crates/typify) and
21//! [progenitor](https://crates.io/crates/progenitor).
22//!
23//! [CBOR]: https://cbor.io/
24//!
25//! # Types
26//!
27//! * [`HexArray<N>`] encodes a fixed-length byte array as a hex
28//! string. (Requires the `hex` feature.)
29//! * [`Base64Vec`] encodes a variable-length byte vector as a base64
30//! string. (Requires the `base64` feature.)
31//!
32//! # Examples
33//!
34//! ```
35//! # #[cfg(feature = "hex")] {
36//! use byte_wrapper::HexArray;
37//!
38//! let h = HexArray::new([0x01, 0x02, 0xab, 0xff]);
39//! assert_eq!(h.to_string(), "0102abff");
40//!
41//! let parsed: HexArray<4> = "0102abff".parse().unwrap();
42//! assert_eq!(parsed, h);
43//! # }
44//! ```
45//!
46//! With the **`serde`** feature:
47//!
48//! ```
49//! # #[cfg(all(feature = "hex", feature = "serde"))] {
50//! use byte_wrapper::HexArray;
51//! use serde::{Deserialize, Serialize};
52//!
53//! #[derive(Serialize, Deserialize)]
54//! struct Record {
55//! checksum: HexArray<32>,
56//! }
57//! # }
58//! ```
59//!
60//! Using `#[serde(with = "...")]` on an existing byte array:
61//!
62//! ```
63//! # #[cfg(all(feature = "hex", feature = "serde"))] {
64//! use byte_wrapper::HexArray;
65//! use serde::{Deserialize, Serialize};
66//!
67//! #[derive(Serialize, Deserialize)]
68//! struct Record {
69//! #[serde(with = "HexArray::<32>")]
70//! checksum: [u8; 32],
71//! }
72//! # }
73//! ```
74//!
75//! # Alternatives
76//!
77//! Several crates solve parts of this problem, often using slightly
78//! different approaches from `byte-wrapper`.
79//!
80//! | feature | `byte-wrapper` | [`serde-human-bytes`] 0.1.2 | [`serde-encoded-bytes`] 0.2.1 | [`serde_with`] 3.17.0 | [`hex-buffer-serde`] 0.4.0 | [`hexutil`] 0.1.0 | [`serde-bytes-repr`] 0.3.0 |
81//! |--------------------------------------|----------------|-----------------------------|-----------------------------|----------------------|----------------------------|--------------------------------------|-----------------------------|
82//! | newtype wrappers | yes | yes (hex only) | no | no | no | no | no |
83//! | [`is_human_readable()`] switch | yes | yes | yes | no | yes | yes | no |
84//! | [`Display`] / [`FromStr`] / [`Deref`]| yes | [`Deref`] only | no | no | no | [`Display`] / [`FromStr`] via macro | no |
85//! | hex encoding | yes | yes | yes | yes | yes | yes | yes |
86//! | base64 encoding | yes | yes | yes | yes | no | no | yes |
87//! | `[u8; N]` support | yes | yes | yes | yes | yes | via macros | no |
88//! | `no_std` | yes | yes | yes | yes | yes | yes | no |
89//! | [`JsonSchema`] (schemars) | yes | no | no | yes | no | no | no |
90//! | `#[serde(with)]` support | yes | yes | yes | yes | yes | no | no |
91//!
92//! The closest alternatives are:
93//!
94//! * [`serde-human-bytes`], which provides
95//! newtypes with [`Deref`], [`is_human_readable()`] switching,
96//! and both hex and base64 encoding, but lacks [`Display`] /
97//! [`FromStr`] and [`JsonSchema`] support.
98//!
99//! * [`serde-encoded-bytes`], which provides most of the features of this
100//! crate, and is more general in some ways, but doesn't provide newtype
101//! or schemars support.
102//!
103//! * [`serde_with`], which offers schemars integration but does not check
104//! [`is_human_readable()`] by default.
105//!
106//! [`serde-encoded-bytes`]: https://docs.rs/serde-encoded-bytes
107//! [`hex-buffer-serde`]: https://docs.rs/hex-buffer-serde
108//! [`hexutil`]: https://docs.rs/hexutil
109//! [`serde_with`]: https://docs.rs/serde_with
110//! [`serde-bytes-repr`]: https://docs.rs/serde-bytes-repr
111//! [`serde-human-bytes`]: https://docs.rs/serde-human-bytes
112//! [`Display`]: core::fmt::Display
113//! [`FromStr`]: core::str::FromStr
114//! [`Deref`]: core::ops::Deref
115//! [`JsonSchema`]: https://docs.rs/schemars/0.8/schemars/trait.JsonSchema.html
116//! [`is_human_readable()`]: https://docs.rs/serde/latest/serde/trait.Serializer.html#method.is_human_readable
117//! [`Hex`]: https://docs.rs/serde_with/latest/serde_with/hex/struct.Hex.html
118//! [`Base64`]: https://docs.rs/serde_with/latest/serde_with/base64/struct.Base64.html
119//!
120//! # Features
121//!
122//! - **`hex`**: enables [`HexArray`]. *Enabled by default.*
123//! - **`base64`**: enables [`Base64Vec`] (implies `alloc`).
124//! *Enabled by default.*
125//! - **`alloc`**: enables `alloc` support (required by `base64`).
126//! - **`serde`**: implements `Serialize` and `Deserialize` for
127//! enabled types. *Not enabled by default.*
128//! - **`schemars08`**: derives `JsonSchema` for enabled types.
129//! *Not enabled by default.*
130
131#![deny(missing_docs)]
132#![no_std]
133#![cfg_attr(doc_cfg, feature(doc_cfg))]
134
135#[cfg(feature = "alloc")]
136extern crate alloc;
137
138#[cfg(feature = "base64")]
139mod base64_vec;
140#[cfg(feature = "hex")]
141mod hex_array;
142#[cfg(all(feature = "schemars08", any(feature = "base64", feature = "hex")))]
143mod schemars_util;
144
145#[cfg(feature = "base64")]
146pub use base64_vec::{Base64Vec, ParseBase64Error};
147#[cfg(feature = "hex")]
148pub use hex_array::{HexArray, ParseHexError};