Skip to main content

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, this crate's 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, this crate's 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//! * [`HexSlice`] encodes a borrowed byte slice as a hex string.
30//!   (Requires the `hex` feature.)
31//! * [`HexVec`] encodes a variable-length byte vector as a hex
32//!   string. (Requires the `hex` and `alloc` features.)
33//! * [`Base64Vec`] encodes a variable-length byte vector as a base64
34//!   string. (Requires the `base64` and `alloc` features.)
35//! * [`Base64Slice`] encodes a borrowed byte slice as a base64 string.
36//!   (Requires the `base64` feature.)
37//!
38//! # Examples
39//!
40//! ```
41//! # #[cfg(feature = "hex")] {
42//! use byte_wrapper::HexArray;
43//!
44//! let h = HexArray::new([0x01, 0x02, 0xab, 0xff]);
45//! assert_eq!(h.to_string(), "0102abff");
46//!
47//! let parsed: HexArray<4> = "0102abff".parse().unwrap();
48//! assert_eq!(parsed, h);
49//! # }
50//! ```
51//!
52//! With the **`serde`** feature:
53//!
54//! ```
55//! # #[cfg(all(feature = "hex", feature = "serde"))] {
56//! use byte_wrapper::HexArray;
57//! use serde::{Deserialize, Serialize};
58//!
59//! #[derive(Serialize, Deserialize)]
60//! struct Record {
61//!     checksum: HexArray<32>,
62//! }
63//! # }
64//! ```
65//!
66//! Using `#[serde(with = "...")]` on an existing byte array:
67//!
68//! ```
69//! # #[cfg(all(feature = "hex", feature = "serde"))] {
70//! use byte_wrapper::HexArray;
71//! use serde::{Deserialize, Serialize};
72//!
73//! #[derive(Serialize, Deserialize)]
74//! struct Record {
75//!     #[serde(with = "HexArray::<32>")]
76//!     checksum: [u8; 32],
77//! }
78//! # }
79//! ```
80//!
81//! # Alternatives
82//!
83//! Several crates solve parts of this problem, often using slightly
84//! different approaches from `byte-wrapper`.
85//!
86//! | 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 |
87//! |--------------------------------------|----------------|-----------------------------|-----------------------------|----------------------|----------------------------|--------------------------------------|-----------------------------|
88//! | newtype wrappers                     | yes            | yes (hex only)              | no                          | no                   | no                         | no                                   | no                          |
89//! | [`is_human_readable()`] switch       | yes            | yes                         | yes                         | no                   | yes                        | yes                                  | no                          |
90//! | [`Display`] / [`FromStr`] / [`Deref`]| yes            | [`Deref`] only              | no                          | no                   | no                         | [`Display`] / [`FromStr`] via macro  | no                          |
91//! | hex encoding                         | yes            | yes                         | yes                         | yes                  | yes                        | yes                                  | yes                         |
92//! | base64 encoding                      | yes            | yes                         | yes                         | yes                  | no                         | no                                   | yes                         |
93//! | `[u8; N]` support                    | yes            | yes                         | yes                         | yes                  | yes                        | via macros                           | no                          |
94//! | `no_std`                             | yes            | yes                         | yes                         | yes                  | yes                        | yes                                  | no                          |
95//! | [`JsonSchema`] (schemars)            | yes            | no                          | no                          | yes                  | no                         | no                                   | no                          |
96//! | `#[serde(with)]` support             | yes            | yes                         | yes                         | yes                  | yes                        | no                                   | no                          |
97//!
98//! The closest alternatives are:
99//!
100//! * [`serde-human-bytes`], which provides
101//!   newtypes with [`Deref`], [`is_human_readable()`] switching,
102//!   and both hex and base64 encoding, but lacks [`Display`] /
103//!   [`FromStr`] and [`JsonSchema`] support.
104//!
105//! * [`serde-encoded-bytes`], which provides most of the features of this
106//!   crate, and is more general in some ways, but doesn't provide newtype
107//!   or schemars support.
108//!
109//! * [`serde_with`], which offers schemars integration but does not check
110//!   [`is_human_readable()`] by default.
111//!
112//! [`serde-encoded-bytes`]: https://docs.rs/serde-encoded-bytes
113//! [`hex-buffer-serde`]: https://docs.rs/hex-buffer-serde
114//! [`hexutil`]: https://docs.rs/hexutil
115//! [`serde_with`]: https://docs.rs/serde_with
116//! [`serde-bytes-repr`]: https://docs.rs/serde-bytes-repr
117//! [`serde-human-bytes`]: https://docs.rs/serde-human-bytes
118//! [`Display`]: core::fmt::Display
119//! [`FromStr`]: core::str::FromStr
120//! [`Deref`]: core::ops::Deref
121//! [`JsonSchema`]: https://docs.rs/schemars/0.8/schemars/trait.JsonSchema.html
122//! [`is_human_readable()`]: https://docs.rs/serde/latest/serde/trait.Serializer.html#method.is_human_readable
123//! [`Hex`]: https://docs.rs/serde_with/latest/serde_with/hex/struct.Hex.html
124//! [`Base64`]: https://docs.rs/serde_with/latest/serde_with/base64/struct.Base64.html
125//!
126//! # Features
127//!
128//! - **`hex`**: enables [`HexArray`] and [`HexSlice`], and [`HexVec`]
129//!   together with `alloc`. *Enabled by default.*
130//! - **`base64`**: enables [`Base64Slice`], and [`Base64Vec`] together with
131//!   `alloc`. *Enabled by default.*
132//! - **`alloc`**: enables `alloc` support (required by [`Base64Vec`] and
133//!   [`HexVec`]). *Enabled by default.*
134//! - **`serde`**: implements `Serialize` and `Deserialize` for
135//!   enabled types. *Not enabled by default.*
136//! - **`schemars08`**: derives `JsonSchema` for enabled types.
137//!   Requires `std`. *Not enabled by default.*
138//!
139//! All features other than `schemars08` are compatible with `no_std`.
140
141#![deny(missing_docs)]
142#![no_std]
143#![cfg_attr(doc_cfg, feature(doc_cfg))]
144
145#[cfg(feature = "alloc")]
146extern crate alloc;
147
148#[cfg(feature = "base64")]
149mod base64_slice;
150#[cfg(all(feature = "base64", feature = "alloc"))]
151mod base64_vec;
152#[cfg(feature = "hex")]
153mod hex_array;
154#[cfg(feature = "hex")]
155mod hex_slice;
156#[cfg(all(feature = "hex", feature = "alloc"))]
157mod hex_vec;
158#[cfg(all(feature = "schemars08", any(feature = "base64", feature = "hex")))]
159mod schemars_util;
160#[cfg(all(
161    feature = "serde",
162    feature = "alloc",
163    any(feature = "base64", feature = "hex")
164))]
165mod serde_util;
166
167#[cfg(feature = "base64")]
168pub use base64_slice::Base64Slice;
169#[cfg(all(feature = "base64", feature = "alloc"))]
170pub use base64_vec::{Base64Vec, ParseBase64Error};
171#[cfg(feature = "hex")]
172pub use hex_array::{HexArray, ParseHexError};
173#[cfg(feature = "hex")]
174pub use hex_slice::HexSlice;
175#[cfg(all(feature = "hex", feature = "alloc"))]
176pub use hex_vec::HexVec;