├── .gitignore ├── tests ├── test_partialeq.rs ├── test_serde.rs └── test_derive.rs ├── LICENSE-MIT ├── Cargo.toml ├── README.md ├── .github └── workflows │ └── ci.yml ├── src ├── lib.rs ├── ser.rs ├── bytes.rs ├── bytebuf.rs ├── bytearray.rs └── de.rs └── LICENSE-APACHE /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /Cargo.lock 3 | -------------------------------------------------------------------------------- /tests/test_partialeq.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::needless_pass_by_value)] 2 | 3 | use serde_bytes::{ByteArray, ByteBuf, Bytes}; 4 | 5 | fn _bytes_eq_slice(bytes: &Bytes, slice: &[u8]) -> bool { 6 | bytes == slice 7 | } 8 | 9 | fn _bytebuf_eq_vec(bytebuf: ByteBuf, vec: Vec) -> bool { 10 | bytebuf == vec 11 | } 12 | 13 | fn _bytes_eq_bytestring(bytes: &Bytes) -> bool { 14 | bytes == b"..." 15 | } 16 | 17 | fn _bytearray_eq_bytestring(bytes: &ByteArray) -> bool { 18 | bytes == &[0u8; N] 19 | } 20 | 21 | fn _bytearray_eq_bytearray(bytes: &ByteArray, other: &ByteArray) -> bool { 22 | bytes == other 23 | } 24 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "serde_bytes" 3 | version = "0.11.19" 4 | authors = ["David Tolnay "] 5 | categories = ["encoding", "no-std", "no-std::no-alloc"] 6 | description = "Optimized handling of `&[u8]` and `Vec` for Serde" 7 | documentation = "https://docs.rs/serde_bytes" 8 | edition = "2021" 9 | keywords = ["serde", "serialization", "no_std", "bytes"] 10 | license = "MIT OR Apache-2.0" 11 | repository = "https://github.com/serde-rs/bytes" 12 | rust-version = "1.68" 13 | 14 | [features] 15 | default = ["std"] 16 | std = ["serde_core/std"] 17 | alloc = ["serde_core/alloc"] 18 | 19 | [dependencies] 20 | serde_core = { version = "1.0.220", default-features = false } 21 | 22 | [target.'cfg(any())'.dependencies] 23 | serde = { version = "1.0.220", default-features = false } 24 | 25 | [dev-dependencies] 26 | bincode = { version = "2", features = ["serde"] } 27 | serde = "1.0.220" 28 | serde_derive = "1.0.220" 29 | serde_test = "1.0.166" 30 | 31 | [package.metadata.docs.rs] 32 | targets = ["x86_64-unknown-linux-gnu"] 33 | rustdoc-args = [ 34 | "--generate-link-to-definition", 35 | "--generate-macro-expansion", 36 | "--extern-html-root-url=core=https://doc.rust-lang.org", 37 | "--extern-html-root-url=alloc=https://doc.rust-lang.org", 38 | "--extern-html-root-url=std=https://doc.rust-lang.org", 39 | ] 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # serde\_bytes [![Build Status](https://img.shields.io/github/actions/workflow/status/serde-rs/bytes/ci.yml?branch=master)](https://github.com/serde-rs/bytes/actions?query=branch%3Amaster) [![Latest Version](https://img.shields.io/crates/v/serde_bytes.svg)](https://crates.io/crates/serde_bytes) 2 | 3 | Wrapper types to enable optimized handling of `&[u8]` and `Vec`. 4 | 5 | ```toml 6 | [dependencies] 7 | serde_bytes = "0.11" 8 | ``` 9 | 10 | ## Explanation 11 | 12 | Without specialization, Rust forces Serde to treat `&[u8]` just like any 13 | other slice and `Vec` just like any other vector. In reality this 14 | particular slice and vector can often be serialized and deserialized in a 15 | more efficient, compact representation in many formats. 16 | 17 | When working with such a format, you can opt into specialized handling of 18 | `&[u8]` by wrapping it in `serde_bytes::Bytes` and `Vec` by wrapping it 19 | in `serde_bytes::ByteBuf`. 20 | 21 | Additionally this crate supports the Serde `with` attribute to enable efficient 22 | handling of `&[u8]` and `Vec` in structs without needing a wrapper type. 23 | 24 | ## Example 25 | 26 | ```rust 27 | use serde::{Deserialize, Serialize}; 28 | 29 | #[derive(Deserialize, Serialize)] 30 | struct Efficient<'a> { 31 | #[serde(with = "serde_bytes")] 32 | bytes: &'a [u8], 33 | 34 | #[serde(with = "serde_bytes")] 35 | byte_buf: Vec, 36 | } 37 | ``` 38 | 39 |
40 | 41 | #### License 42 | 43 | 44 | Licensed under either of Apache License, Version 45 | 2.0 or MIT license at your option. 46 | 47 | 48 |
49 | 50 | 51 | Unless you explicitly state otherwise, any contribution intentionally submitted 52 | for inclusion in this crate by you, as defined in the Apache-2.0 license, shall 53 | be dual licensed as above, without any additional terms or conditions. 54 | 55 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | schedule: [cron: "40 1 * * *"] 8 | 9 | permissions: 10 | contents: read 11 | 12 | env: 13 | RUSTFLAGS: -Dwarnings 14 | 15 | jobs: 16 | test: 17 | name: Rust ${{matrix.rust}} 18 | runs-on: ubuntu-latest 19 | strategy: 20 | fail-fast: false 21 | matrix: 22 | rust: [nightly, beta, stable, 1.85.0, 1.68.0] 23 | timeout-minutes: 45 24 | steps: 25 | - uses: actions/checkout@v6 26 | - uses: dtolnay/rust-toolchain@master 27 | with: 28 | toolchain: ${{matrix.rust}} 29 | - run: cargo check --no-default-features 30 | - run: cargo check --no-default-features --features alloc 31 | - run: cargo test 32 | if: matrix.rust != '1.68.0' 33 | - uses: actions/upload-artifact@v6 34 | if: matrix.rust == 'nightly' && always() 35 | with: 36 | name: Cargo.lock 37 | path: Cargo.lock 38 | continue-on-error: true 39 | 40 | minimal: 41 | name: Minimal versions 42 | runs-on: ubuntu-latest 43 | timeout-minutes: 45 44 | steps: 45 | - uses: actions/checkout@v6 46 | - uses: dtolnay/rust-toolchain@nightly 47 | - run: cargo generate-lockfile -Z minimal-versions 48 | - run: cargo check --locked 49 | 50 | doc: 51 | name: Documentation 52 | runs-on: ubuntu-latest 53 | timeout-minutes: 45 54 | env: 55 | RUSTDOCFLAGS: -Dwarnings 56 | steps: 57 | - uses: actions/checkout@v6 58 | - uses: dtolnay/rust-toolchain@nightly 59 | - uses: dtolnay/install@cargo-docs-rs 60 | - run: cargo docs-rs 61 | 62 | clippy: 63 | name: Clippy 64 | runs-on: ubuntu-latest 65 | if: github.event_name != 'pull_request' 66 | timeout-minutes: 45 67 | steps: 68 | - uses: actions/checkout@v6 69 | - uses: dtolnay/rust-toolchain@clippy 70 | - run: cargo clippy --tests -- -Dclippy::all -Dclippy::pedantic 71 | 72 | outdated: 73 | name: Outdated 74 | runs-on: ubuntu-latest 75 | if: github.event_name != 'pull_request' 76 | timeout-minutes: 45 77 | steps: 78 | - uses: actions/checkout@v6 79 | - uses: dtolnay/rust-toolchain@stable 80 | - uses: dtolnay/install@cargo-outdated 81 | - run: cargo outdated --workspace --ignore bincode --exit-code 1 82 | -------------------------------------------------------------------------------- /tests/test_serde.rs: -------------------------------------------------------------------------------- 1 | use serde_bytes::{ByteArray, ByteBuf, Bytes}; 2 | use serde_test::{assert_de_tokens, assert_ser_tokens, assert_tokens, Token}; 3 | 4 | #[test] 5 | fn test_bytes() { 6 | let empty = Bytes::new(&[]); 7 | assert_tokens(&empty, &[Token::BorrowedBytes(b"")]); 8 | assert_ser_tokens(&empty, &[Token::Bytes(b"")]); 9 | assert_ser_tokens(&empty, &[Token::ByteBuf(b"")]); 10 | assert_de_tokens(&empty, &[Token::BorrowedStr("")]); 11 | 12 | let buf = vec![65, 66, 67]; 13 | let bytes = Bytes::new(&buf); 14 | assert_tokens(&bytes, &[Token::BorrowedBytes(b"ABC")]); 15 | assert_ser_tokens(&bytes, &[Token::Bytes(b"ABC")]); 16 | assert_ser_tokens(&bytes, &[Token::ByteBuf(b"ABC")]); 17 | assert_de_tokens(&bytes, &[Token::BorrowedStr("ABC")]); 18 | } 19 | 20 | #[test] 21 | fn test_byte_buf() { 22 | let empty = ByteBuf::new(); 23 | assert_tokens(&empty, &[Token::BorrowedBytes(b"")]); 24 | assert_tokens(&empty, &[Token::Bytes(b"")]); 25 | assert_tokens(&empty, &[Token::ByteBuf(b"")]); 26 | assert_de_tokens(&empty, &[Token::BorrowedStr("")]); 27 | assert_de_tokens(&empty, &[Token::Str("")]); 28 | assert_de_tokens(&empty, &[Token::String("")]); 29 | assert_de_tokens(&empty, &[Token::Seq { len: None }, Token::SeqEnd]); 30 | assert_de_tokens(&empty, &[Token::Seq { len: Some(0) }, Token::SeqEnd]); 31 | 32 | let buf = ByteBuf::from(vec![65, 66, 67]); 33 | assert_tokens(&buf, &[Token::BorrowedBytes(b"ABC")]); 34 | assert_tokens(&buf, &[Token::Bytes(b"ABC")]); 35 | assert_tokens(&buf, &[Token::ByteBuf(b"ABC")]); 36 | assert_de_tokens(&buf, &[Token::BorrowedStr("ABC")]); 37 | assert_de_tokens(&buf, &[Token::Str("ABC")]); 38 | assert_de_tokens(&buf, &[Token::String("ABC")]); 39 | assert_de_tokens( 40 | &buf, 41 | &[ 42 | Token::Seq { len: None }, 43 | Token::U8(65), 44 | Token::U8(66), 45 | Token::U8(67), 46 | Token::SeqEnd, 47 | ], 48 | ); 49 | assert_de_tokens( 50 | &buf, 51 | &[ 52 | Token::Seq { len: Some(3) }, 53 | Token::U8(65), 54 | Token::U8(66), 55 | Token::U8(67), 56 | Token::SeqEnd, 57 | ], 58 | ); 59 | } 60 | 61 | #[test] 62 | fn test_bytearray() { 63 | let empty = ByteArray::new([]); 64 | assert_tokens(&empty, &[Token::BorrowedBytes(b"")]); 65 | assert_ser_tokens(&empty, &[Token::Bytes(b"")]); 66 | assert_ser_tokens(&empty, &[Token::ByteBuf(b"")]); 67 | assert_de_tokens(&empty, &[Token::BorrowedStr("")]); 68 | 69 | let buf = [65, 66, 67]; 70 | let bytes = ByteArray::new(buf); 71 | assert_tokens(&bytes, &[Token::BorrowedBytes(b"ABC")]); 72 | assert_ser_tokens(&bytes, &[Token::Bytes(b"ABC")]); 73 | assert_ser_tokens(&bytes, &[Token::ByteBuf(b"ABC")]); 74 | assert_de_tokens(&bytes, &[Token::BorrowedStr("ABC")]); 75 | } 76 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Wrapper types to enable optimized handling of `&[u8]` and `Vec`. 2 | //! 3 | //! Without specialization, Rust forces Serde to treat `&[u8]` just like any 4 | //! other slice and `Vec` just like any other vector. In reality this 5 | //! particular slice and vector can often be serialized and deserialized in a 6 | //! more efficient, compact representation in many formats. 7 | //! 8 | //! When working with such a format, you can opt into specialized handling of 9 | //! `&[u8]` by wrapping it in `serde_bytes::Bytes` and `Vec` by wrapping it 10 | //! in `serde_bytes::ByteBuf`. 11 | //! 12 | //! Additionally this crate supports the Serde `with` attribute to enable 13 | //! efficient handling of `&[u8]` and `Vec` in structs without needing a 14 | //! wrapper type. 15 | //! 16 | //! ``` 17 | //! # use serde_derive::{Deserialize, Serialize}; 18 | //! use serde::{Deserialize, Serialize}; 19 | //! 20 | //! #[derive(Deserialize, Serialize)] 21 | //! struct Efficient<'a> { 22 | //! #[serde(with = "serde_bytes")] 23 | //! bytes: &'a [u8], 24 | //! 25 | //! #[serde(with = "serde_bytes")] 26 | //! byte_buf: Vec, 27 | //! 28 | //! #[serde(with = "serde_bytes")] 29 | //! byte_array: [u8; 314], 30 | //! } 31 | //! ``` 32 | 33 | #![doc(html_root_url = "https://docs.rs/serde_bytes/0.11.19")] 34 | #![cfg_attr(not(feature = "std"), no_std)] 35 | #![deny(missing_docs)] 36 | #![allow( 37 | clippy::elidable_lifetime_names, 38 | clippy::into_iter_without_iter, 39 | clippy::missing_errors_doc, 40 | clippy::must_use_candidate, 41 | clippy::needless_doctest_main, 42 | clippy::needless_lifetimes 43 | )] 44 | 45 | extern crate serde_core as serde; 46 | 47 | mod bytearray; 48 | mod bytes; 49 | mod de; 50 | mod ser; 51 | 52 | #[cfg(any(feature = "std", feature = "alloc"))] 53 | mod bytebuf; 54 | 55 | #[cfg(feature = "alloc")] 56 | extern crate alloc; 57 | 58 | use serde::{Deserializer, Serializer}; 59 | 60 | pub use crate::bytearray::ByteArray; 61 | pub use crate::bytes::Bytes; 62 | pub use crate::de::Deserialize; 63 | pub use crate::ser::Serialize; 64 | 65 | #[cfg(any(feature = "std", feature = "alloc"))] 66 | pub use crate::bytebuf::ByteBuf; 67 | 68 | /// Serde `serialize_with` function to serialize bytes efficiently. 69 | /// 70 | /// This function can be used with either of the following Serde attributes: 71 | /// 72 | /// - `#[serde(with = "serde_bytes")]` 73 | /// - `#[serde(serialize_with = "serde_bytes::serialize")]` 74 | /// 75 | /// ``` 76 | /// # use serde_derive::Serialize; 77 | /// use serde::Serialize; 78 | /// 79 | /// #[derive(Serialize)] 80 | /// struct Efficient<'a> { 81 | /// #[serde(with = "serde_bytes")] 82 | /// bytes: &'a [u8], 83 | /// 84 | /// #[serde(with = "serde_bytes")] 85 | /// byte_buf: Vec, 86 | /// 87 | /// #[serde(with = "serde_bytes")] 88 | /// byte_array: [u8; 314], 89 | /// } 90 | /// ``` 91 | pub fn serialize(bytes: &T, serializer: S) -> Result 92 | where 93 | T: ?Sized + Serialize, 94 | S: Serializer, 95 | { 96 | Serialize::serialize(bytes, serializer) 97 | } 98 | 99 | /// Serde `deserialize_with` function to deserialize bytes efficiently. 100 | /// 101 | /// This function can be used with either of the following Serde attributes: 102 | /// 103 | /// - `#[serde(with = "serde_bytes")]` 104 | /// - `#[serde(deserialize_with = "serde_bytes::deserialize")]` 105 | /// 106 | /// ``` 107 | /// # use serde_derive::Deserialize; 108 | /// use serde::Deserialize; 109 | /// 110 | /// #[derive(Deserialize)] 111 | /// struct Packet { 112 | /// #[serde(with = "serde_bytes")] 113 | /// payload: Vec, 114 | /// 115 | /// #[serde(with = "serde_bytes")] 116 | /// byte_array: [u8; 314], 117 | /// } 118 | /// ``` 119 | pub fn deserialize<'de, T, D>(deserializer: D) -> Result 120 | where 121 | T: Deserialize<'de>, 122 | D: Deserializer<'de>, 123 | { 124 | Deserialize::deserialize(deserializer) 125 | } 126 | -------------------------------------------------------------------------------- /src/ser.rs: -------------------------------------------------------------------------------- 1 | use crate::{ByteArray, Bytes}; 2 | use serde::Serializer; 3 | 4 | #[cfg(any(feature = "std", feature = "alloc"))] 5 | use crate::ByteBuf; 6 | 7 | #[cfg(feature = "alloc")] 8 | use alloc::borrow::Cow; 9 | #[cfg(all(feature = "std", not(feature = "alloc")))] 10 | use std::borrow::Cow; 11 | 12 | #[cfg(feature = "alloc")] 13 | use alloc::boxed::Box; 14 | 15 | #[cfg(feature = "alloc")] 16 | use alloc::vec::Vec; 17 | 18 | /// Types that can be serialized via `#[serde(with = "serde_bytes")]`. 19 | pub trait Serialize { 20 | #[allow(missing_docs)] 21 | fn serialize(&self, serializer: S) -> Result 22 | where 23 | S: Serializer; 24 | } 25 | 26 | impl Serialize for [u8] { 27 | fn serialize(&self, serializer: S) -> Result 28 | where 29 | S: Serializer, 30 | { 31 | serializer.serialize_bytes(self) 32 | } 33 | } 34 | 35 | #[cfg(any(feature = "std", feature = "alloc"))] 36 | impl Serialize for Vec { 37 | fn serialize(&self, serializer: S) -> Result 38 | where 39 | S: Serializer, 40 | { 41 | serializer.serialize_bytes(self) 42 | } 43 | } 44 | 45 | impl Serialize for Bytes { 46 | fn serialize(&self, serializer: S) -> Result 47 | where 48 | S: Serializer, 49 | { 50 | serializer.serialize_bytes(self) 51 | } 52 | } 53 | 54 | impl Serialize for [u8; N] { 55 | fn serialize(&self, serializer: S) -> Result 56 | where 57 | S: Serializer, 58 | { 59 | serializer.serialize_bytes(self) 60 | } 61 | } 62 | 63 | impl Serialize for ByteArray { 64 | fn serialize(&self, serializer: S) -> Result 65 | where 66 | S: Serializer, 67 | { 68 | serializer.serialize_bytes(&**self) 69 | } 70 | } 71 | 72 | #[cfg(any(feature = "std", feature = "alloc"))] 73 | impl Serialize for ByteBuf { 74 | fn serialize(&self, serializer: S) -> Result 75 | where 76 | S: Serializer, 77 | { 78 | serializer.serialize_bytes(self) 79 | } 80 | } 81 | 82 | #[cfg(any(feature = "std", feature = "alloc"))] 83 | impl<'a> Serialize for Cow<'a, [u8]> { 84 | fn serialize(&self, serializer: S) -> Result 85 | where 86 | S: Serializer, 87 | { 88 | serializer.serialize_bytes(self) 89 | } 90 | } 91 | 92 | #[cfg(any(feature = "std", feature = "alloc"))] 93 | impl<'a> Serialize for Cow<'a, Bytes> { 94 | fn serialize(&self, serializer: S) -> Result 95 | where 96 | S: Serializer, 97 | { 98 | serializer.serialize_bytes(self) 99 | } 100 | } 101 | 102 | impl Serialize for &T 103 | where 104 | T: ?Sized + Serialize, 105 | { 106 | fn serialize(&self, serializer: S) -> Result 107 | where 108 | S: Serializer, 109 | { 110 | (**self).serialize(serializer) 111 | } 112 | } 113 | 114 | #[cfg(any(feature = "std", feature = "alloc"))] 115 | impl Serialize for Box 116 | where 117 | T: ?Sized + Serialize, 118 | { 119 | fn serialize(&self, serializer: S) -> Result 120 | where 121 | S: Serializer, 122 | { 123 | (**self).serialize(serializer) 124 | } 125 | } 126 | 127 | impl Serialize for Option 128 | where 129 | T: Serialize, 130 | { 131 | fn serialize(&self, serializer: S) -> Result 132 | where 133 | S: Serializer, 134 | { 135 | struct AsBytes(T); 136 | 137 | impl serde::Serialize for AsBytes 138 | where 139 | T: Serialize, 140 | { 141 | fn serialize(&self, serializer: S) -> Result 142 | where 143 | S: Serializer, 144 | { 145 | self.0.serialize(serializer) 146 | } 147 | } 148 | 149 | match self { 150 | Some(b) => serializer.serialize_some(&AsBytes(b)), 151 | None => serializer.serialize_none(), 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /tests/test_derive.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::derive_partial_eq_without_eq, clippy::ref_option_ref)] 2 | 3 | use serde_bytes::{ByteArray, ByteBuf, Bytes}; 4 | use serde_derive::{Deserialize, Serialize}; 5 | use serde_test::{assert_tokens, Token}; 6 | use std::borrow::Cow; 7 | 8 | #[derive(Serialize, Deserialize, PartialEq, Debug)] 9 | struct Test<'a> { 10 | #[serde(with = "serde_bytes")] 11 | slice: &'a [u8], 12 | 13 | #[serde(with = "serde_bytes")] 14 | array: [u8; 314], 15 | 16 | #[serde(with = "serde_bytes")] 17 | borrowed_array: &'a [u8; 314], 18 | 19 | #[serde(with = "serde_bytes")] 20 | vec: Vec, 21 | 22 | #[serde(with = "serde_bytes")] 23 | bytes: &'a Bytes, 24 | 25 | #[serde(with = "serde_bytes")] 26 | byte_array: ByteArray<314>, 27 | 28 | #[serde(with = "serde_bytes")] 29 | borrowed_byte_array: &'a ByteArray<314>, 30 | 31 | #[serde(with = "serde_bytes")] 32 | byte_buf: ByteBuf, 33 | 34 | #[serde(with = "serde_bytes")] 35 | cow_slice: Cow<'a, [u8]>, 36 | 37 | #[serde(with = "serde_bytes")] 38 | cow_bytes: Cow<'a, Bytes>, 39 | 40 | #[serde(with = "serde_bytes")] 41 | boxed_slice: Box<[u8]>, 42 | 43 | #[serde(with = "serde_bytes")] 44 | boxed_bytes: Box, 45 | 46 | #[serde(with = "serde_bytes")] 47 | opt_slice: Option<&'a [u8]>, 48 | 49 | #[serde(with = "serde_bytes")] 50 | opt_vec: Option>, 51 | 52 | #[serde(with = "serde_bytes")] 53 | opt_array: Option<[u8; 314]>, 54 | 55 | #[serde(with = "serde_bytes")] 56 | opt_bytearray: Option>, 57 | 58 | #[serde(with = "serde_bytes")] 59 | opt_cow_slice: Option>, 60 | } 61 | 62 | #[derive(Serialize)] 63 | #[allow(dead_code)] 64 | struct Dst { 65 | #[serde(with = "serde_bytes")] 66 | bytes: [u8], 67 | } 68 | 69 | #[test] 70 | fn test() { 71 | let test = Test { 72 | slice: b"...", 73 | array: [0; 314], 74 | borrowed_array: &[1; 314], 75 | vec: b"...".to_vec(), 76 | bytes: Bytes::new(b"..."), 77 | byte_array: ByteArray::new([0; 314]), 78 | borrowed_byte_array: &ByteArray::new([0; 314]), 79 | byte_buf: ByteBuf::from(b"...".as_ref()), 80 | cow_slice: Cow::Borrowed(b"..."), 81 | cow_bytes: Cow::Borrowed(Bytes::new(b"...")), 82 | boxed_slice: b"...".to_vec().into_boxed_slice(), 83 | boxed_bytes: ByteBuf::from(b"...".as_ref()).into_boxed_bytes(), 84 | opt_slice: Some(b"..."), 85 | opt_vec: Some(b"...".to_vec()), 86 | opt_array: Some([0; 314]), 87 | opt_bytearray: Some(ByteArray::new([0; 314])), 88 | opt_cow_slice: Some(Cow::Borrowed(b"...")), 89 | }; 90 | 91 | assert_tokens( 92 | &test, 93 | &[ 94 | Token::Struct { 95 | name: "Test", 96 | len: 17, 97 | }, 98 | Token::Str("slice"), 99 | Token::BorrowedBytes(b"..."), 100 | Token::Str("array"), 101 | Token::Bytes(&[0; 314]), 102 | Token::Str("borrowed_array"), 103 | Token::BorrowedBytes(&[1; 314]), 104 | Token::Str("vec"), 105 | Token::Bytes(b"..."), 106 | Token::Str("bytes"), 107 | Token::BorrowedBytes(b"..."), 108 | Token::Str("byte_array"), 109 | Token::Bytes(&[0; 314]), 110 | Token::Str("borrowed_byte_array"), 111 | Token::BorrowedBytes(&[0; 314]), 112 | Token::Str("byte_buf"), 113 | Token::Bytes(b"..."), 114 | Token::Str("cow_slice"), 115 | Token::BorrowedBytes(b"..."), 116 | Token::Str("cow_bytes"), 117 | Token::BorrowedBytes(b"..."), 118 | Token::Str("boxed_slice"), 119 | Token::Bytes(b"..."), 120 | Token::Str("boxed_bytes"), 121 | Token::Bytes(b"..."), 122 | Token::Str("opt_slice"), 123 | Token::Some, 124 | Token::BorrowedBytes(b"..."), 125 | Token::Str("opt_vec"), 126 | Token::Some, 127 | Token::Bytes(b"..."), 128 | Token::Str("opt_array"), 129 | Token::Some, 130 | Token::Bytes(&[0; 314]), 131 | Token::Str("opt_bytearray"), 132 | Token::Some, 133 | Token::Bytes(&[0; 314]), 134 | Token::Str("opt_cow_slice"), 135 | Token::Some, 136 | Token::BorrowedBytes(b"..."), 137 | Token::StructEnd, 138 | ], 139 | ); 140 | } 141 | -------------------------------------------------------------------------------- /src/bytes.rs: -------------------------------------------------------------------------------- 1 | use core::cmp::Ordering; 2 | use core::fmt::{self, Debug}; 3 | use core::hash::{Hash, Hasher}; 4 | use core::ops::{Deref, DerefMut}; 5 | 6 | #[cfg(feature = "alloc")] 7 | use alloc::borrow::ToOwned; 8 | 9 | #[cfg(feature = "alloc")] 10 | use alloc::boxed::Box; 11 | 12 | #[cfg(any(feature = "std", feature = "alloc"))] 13 | use crate::ByteBuf; 14 | 15 | use serde::de::{Deserialize, Deserializer}; 16 | use serde::ser::{Serialize, Serializer}; 17 | 18 | /// Wrapper around `[u8]` to serialize and deserialize efficiently. 19 | /// 20 | /// ``` 21 | /// use std::collections::HashMap; 22 | /// use std::io; 23 | /// 24 | /// use serde_bytes::Bytes; 25 | /// 26 | /// fn print_encoded_cache() -> Result<(), bincode::error::EncodeError> { 27 | /// let mut cache = HashMap::new(); 28 | /// cache.insert(3, Bytes::new(b"three")); 29 | /// cache.insert(2, Bytes::new(b"two")); 30 | /// cache.insert(1, Bytes::new(b"one")); 31 | /// 32 | /// bincode::serde::encode_into_std_write( 33 | /// &cache, 34 | /// &mut io::stdout(), 35 | /// bincode::config::standard(), 36 | /// )?; 37 | /// 38 | /// Ok(()) 39 | /// } 40 | /// # 41 | /// # fn main() { 42 | /// # print_encoded_cache().unwrap(); 43 | /// # } 44 | /// ``` 45 | #[derive(Eq, Ord)] 46 | #[repr(transparent)] 47 | pub struct Bytes { 48 | bytes: [u8], 49 | } 50 | 51 | impl Bytes { 52 | /// Wrap an existing `&[u8]`. 53 | pub fn new(bytes: &[u8]) -> &Self { 54 | unsafe { &*(bytes as *const [u8] as *const Bytes) } 55 | } 56 | } 57 | 58 | impl Debug for Bytes { 59 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 60 | Debug::fmt(&self.bytes, f) 61 | } 62 | } 63 | 64 | impl AsRef<[u8]> for Bytes { 65 | fn as_ref(&self) -> &[u8] { 66 | &self.bytes 67 | } 68 | } 69 | 70 | impl AsMut<[u8]> for Bytes { 71 | fn as_mut(&mut self) -> &mut [u8] { 72 | &mut self.bytes 73 | } 74 | } 75 | 76 | impl Deref for Bytes { 77 | type Target = [u8]; 78 | 79 | fn deref(&self) -> &Self::Target { 80 | &self.bytes 81 | } 82 | } 83 | 84 | impl DerefMut for Bytes { 85 | fn deref_mut(&mut self) -> &mut Self::Target { 86 | &mut self.bytes 87 | } 88 | } 89 | 90 | impl<'a> From<&'a [u8]> for &'a Bytes { 91 | fn from(bytes: &'a [u8]) -> Self { 92 | Bytes::new(bytes) 93 | } 94 | } 95 | 96 | #[cfg(any(feature = "std", feature = "alloc"))] 97 | impl ToOwned for Bytes { 98 | type Owned = ByteBuf; 99 | 100 | fn to_owned(&self) -> Self::Owned { 101 | ByteBuf::from(&self.bytes) 102 | } 103 | } 104 | 105 | #[cfg(any(feature = "std", feature = "alloc"))] 106 | impl From> for Box { 107 | fn from(bytes: Box<[u8]>) -> Self { 108 | unsafe { Box::from_raw(Box::into_raw(bytes) as *mut Bytes) } 109 | } 110 | } 111 | 112 | impl Default for &Bytes { 113 | fn default() -> Self { 114 | Bytes::new(&[]) 115 | } 116 | } 117 | 118 | #[cfg(any(feature = "std", feature = "alloc"))] 119 | impl Default for Box { 120 | fn default() -> Self { 121 | ByteBuf::new().into_boxed_bytes() 122 | } 123 | } 124 | 125 | impl PartialEq for Bytes 126 | where 127 | Rhs: ?Sized + AsRef<[u8]>, 128 | { 129 | fn eq(&self, other: &Rhs) -> bool { 130 | self.as_ref().eq(other.as_ref()) 131 | } 132 | } 133 | 134 | impl PartialOrd for Bytes 135 | where 136 | Rhs: ?Sized + AsRef<[u8]>, 137 | { 138 | fn partial_cmp(&self, other: &Rhs) -> Option { 139 | self.as_ref().partial_cmp(other.as_ref()) 140 | } 141 | } 142 | 143 | impl Hash for Bytes { 144 | fn hash(&self, state: &mut H) { 145 | self.bytes.hash(state); 146 | } 147 | } 148 | 149 | impl<'a> IntoIterator for &'a Bytes { 150 | type Item = &'a u8; 151 | type IntoIter = <&'a [u8] as IntoIterator>::IntoIter; 152 | 153 | fn into_iter(self) -> Self::IntoIter { 154 | self.bytes.iter() 155 | } 156 | } 157 | 158 | impl<'a> IntoIterator for &'a mut Bytes { 159 | type Item = &'a mut u8; 160 | type IntoIter = <&'a mut [u8] as IntoIterator>::IntoIter; 161 | 162 | fn into_iter(self) -> Self::IntoIter { 163 | self.bytes.iter_mut() 164 | } 165 | } 166 | 167 | impl Serialize for Bytes { 168 | fn serialize(&self, serializer: S) -> Result 169 | where 170 | S: Serializer, 171 | { 172 | serializer.serialize_bytes(&self.bytes) 173 | } 174 | } 175 | 176 | impl<'a, 'de: 'a> Deserialize<'de> for &'a Bytes { 177 | fn deserialize(deserializer: D) -> Result 178 | where 179 | D: Deserializer<'de>, 180 | { 181 | // serde::Deserialize for &[u8] is already optimized, so simply forward to that. 182 | Deserialize::deserialize(deserializer).map(Bytes::new) 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /src/bytebuf.rs: -------------------------------------------------------------------------------- 1 | use core::borrow::{Borrow, BorrowMut}; 2 | use core::cmp::{self, Ordering}; 3 | use core::fmt::{self, Debug}; 4 | use core::hash::{Hash, Hasher}; 5 | use core::ops::{Deref, DerefMut}; 6 | 7 | #[cfg(feature = "alloc")] 8 | use alloc::boxed::Box; 9 | #[cfg(feature = "alloc")] 10 | use alloc::string::String; 11 | #[cfg(feature = "alloc")] 12 | use alloc::vec::Vec; 13 | 14 | use serde::de::{Deserialize, Deserializer, Error, SeqAccess, Visitor}; 15 | use serde::ser::{Serialize, Serializer}; 16 | 17 | use crate::Bytes; 18 | 19 | /// Wrapper around `Vec` to serialize and deserialize efficiently. 20 | /// 21 | /// ``` 22 | /// use std::collections::HashMap; 23 | /// use std::io; 24 | /// 25 | /// use serde_bytes::ByteBuf; 26 | /// 27 | /// fn deserialize_bytebufs() -> Result<(), bincode::error::DecodeError> { 28 | /// let example_data = [2, 2, 3, 116, 119, 111, 1, 3, 111, 110, 101]; 29 | /// 30 | /// let map: HashMap; 31 | /// (map, _) = bincode::serde::decode_from_slice( 32 | /// &example_data, 33 | /// bincode::config::standard(), 34 | /// )?; 35 | /// 36 | /// println!("{:?}", map); 37 | /// 38 | /// Ok(()) 39 | /// } 40 | /// # 41 | /// # fn main() { 42 | /// # deserialize_bytebufs().unwrap(); 43 | /// # } 44 | /// ``` 45 | #[derive(Clone, Default, Eq, Ord)] 46 | pub struct ByteBuf { 47 | bytes: Vec, 48 | } 49 | 50 | impl ByteBuf { 51 | /// Construct a new, empty `ByteBuf`. 52 | pub fn new() -> Self { 53 | ByteBuf::from(Vec::new()) 54 | } 55 | 56 | /// Construct a new, empty `ByteBuf` with the specified capacity. 57 | pub fn with_capacity(cap: usize) -> Self { 58 | ByteBuf::from(Vec::with_capacity(cap)) 59 | } 60 | 61 | /// Wrap existing bytes in a `ByteBuf`. 62 | pub fn from>>(bytes: T) -> Self { 63 | ByteBuf { 64 | bytes: bytes.into(), 65 | } 66 | } 67 | 68 | /// Unwrap the vector of byte underlying this `ByteBuf`. 69 | pub fn into_vec(self) -> Vec { 70 | self.bytes 71 | } 72 | 73 | #[allow(missing_docs)] 74 | pub fn into_boxed_bytes(self) -> Box { 75 | self.bytes.into_boxed_slice().into() 76 | } 77 | 78 | // This would hit "cannot move out of borrowed content" if invoked through 79 | // the Deref impl; make it just work. 80 | #[doc(hidden)] 81 | pub fn into_boxed_slice(self) -> Box<[u8]> { 82 | self.bytes.into_boxed_slice() 83 | } 84 | 85 | #[doc(hidden)] 86 | #[allow(clippy::should_implement_trait)] 87 | pub fn into_iter(self) -> as IntoIterator>::IntoIter { 88 | self.bytes.into_iter() 89 | } 90 | } 91 | 92 | impl Debug for ByteBuf { 93 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 94 | Debug::fmt(&self.bytes, f) 95 | } 96 | } 97 | 98 | impl AsRef<[u8]> for ByteBuf { 99 | fn as_ref(&self) -> &[u8] { 100 | &self.bytes 101 | } 102 | } 103 | 104 | impl AsMut<[u8]> for ByteBuf { 105 | fn as_mut(&mut self) -> &mut [u8] { 106 | &mut self.bytes 107 | } 108 | } 109 | 110 | impl Deref for ByteBuf { 111 | type Target = Vec; 112 | 113 | fn deref(&self) -> &Self::Target { 114 | &self.bytes 115 | } 116 | } 117 | 118 | impl DerefMut for ByteBuf { 119 | fn deref_mut(&mut self) -> &mut Self::Target { 120 | &mut self.bytes 121 | } 122 | } 123 | 124 | impl Borrow for ByteBuf { 125 | fn borrow(&self) -> &Bytes { 126 | Bytes::new(&self.bytes) 127 | } 128 | } 129 | 130 | impl BorrowMut for ByteBuf { 131 | fn borrow_mut(&mut self) -> &mut Bytes { 132 | unsafe { &mut *(&mut self.bytes as &mut [u8] as *mut [u8] as *mut Bytes) } 133 | } 134 | } 135 | 136 | impl From> for ByteBuf { 137 | fn from(bytes: Vec) -> Self { 138 | ByteBuf { bytes } 139 | } 140 | } 141 | 142 | impl PartialEq for ByteBuf 143 | where 144 | Rhs: ?Sized + AsRef<[u8]>, 145 | { 146 | fn eq(&self, other: &Rhs) -> bool { 147 | self.as_ref().eq(other.as_ref()) 148 | } 149 | } 150 | 151 | impl PartialOrd for ByteBuf 152 | where 153 | Rhs: ?Sized + AsRef<[u8]>, 154 | { 155 | fn partial_cmp(&self, other: &Rhs) -> Option { 156 | self.as_ref().partial_cmp(other.as_ref()) 157 | } 158 | } 159 | 160 | impl Hash for ByteBuf { 161 | fn hash(&self, state: &mut H) { 162 | self.bytes.hash(state); 163 | } 164 | } 165 | 166 | impl IntoIterator for ByteBuf { 167 | type Item = u8; 168 | type IntoIter = as IntoIterator>::IntoIter; 169 | 170 | fn into_iter(self) -> Self::IntoIter { 171 | self.bytes.into_iter() 172 | } 173 | } 174 | 175 | impl<'a> IntoIterator for &'a ByteBuf { 176 | type Item = &'a u8; 177 | type IntoIter = <&'a [u8] as IntoIterator>::IntoIter; 178 | 179 | fn into_iter(self) -> Self::IntoIter { 180 | self.bytes.iter() 181 | } 182 | } 183 | 184 | impl<'a> IntoIterator for &'a mut ByteBuf { 185 | type Item = &'a mut u8; 186 | type IntoIter = <&'a mut [u8] as IntoIterator>::IntoIter; 187 | 188 | fn into_iter(self) -> Self::IntoIter { 189 | self.bytes.iter_mut() 190 | } 191 | } 192 | 193 | impl Serialize for ByteBuf { 194 | fn serialize(&self, serializer: S) -> Result 195 | where 196 | S: Serializer, 197 | { 198 | serializer.serialize_bytes(&self.bytes) 199 | } 200 | } 201 | 202 | struct ByteBufVisitor; 203 | 204 | impl<'de> Visitor<'de> for ByteBufVisitor { 205 | type Value = ByteBuf; 206 | 207 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 208 | formatter.write_str("byte array") 209 | } 210 | 211 | fn visit_seq(self, mut visitor: V) -> Result 212 | where 213 | V: SeqAccess<'de>, 214 | { 215 | let len = cmp::min(visitor.size_hint().unwrap_or(0), 4096); 216 | let mut bytes = Vec::with_capacity(len); 217 | 218 | while let Some(b) = visitor.next_element()? { 219 | bytes.push(b); 220 | } 221 | 222 | Ok(ByteBuf::from(bytes)) 223 | } 224 | 225 | fn visit_bytes(self, v: &[u8]) -> Result 226 | where 227 | E: Error, 228 | { 229 | Ok(ByteBuf::from(v)) 230 | } 231 | 232 | fn visit_byte_buf(self, v: Vec) -> Result 233 | where 234 | E: Error, 235 | { 236 | Ok(ByteBuf::from(v)) 237 | } 238 | 239 | fn visit_str(self, v: &str) -> Result 240 | where 241 | E: Error, 242 | { 243 | Ok(ByteBuf::from(v)) 244 | } 245 | 246 | fn visit_string(self, v: String) -> Result 247 | where 248 | E: Error, 249 | { 250 | Ok(ByteBuf::from(v)) 251 | } 252 | } 253 | 254 | impl<'de> Deserialize<'de> for ByteBuf { 255 | fn deserialize(deserializer: D) -> Result 256 | where 257 | D: Deserializer<'de>, 258 | { 259 | deserializer.deserialize_byte_buf(ByteBufVisitor) 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /src/bytearray.rs: -------------------------------------------------------------------------------- 1 | use crate::Bytes; 2 | use core::borrow::{Borrow, BorrowMut}; 3 | use core::cmp::Ordering; 4 | use core::fmt::{self, Debug}; 5 | use core::hash::{Hash, Hasher}; 6 | use core::ops::{Deref, DerefMut}; 7 | use core::ptr; 8 | 9 | use serde::de::{Deserialize, Deserializer, Error, SeqAccess, Visitor}; 10 | use serde::ser::{Serialize, Serializer}; 11 | 12 | /// Wrapper around `[u8; N]` to serialize and deserialize efficiently. 13 | /// 14 | /// ``` 15 | /// use std::collections::HashMap; 16 | /// use std::io; 17 | /// 18 | /// use serde_bytes::ByteArray; 19 | /// 20 | /// fn deserialize_bytearrays() -> Result<(), bincode::error::DecodeError> { 21 | /// let example_data = [2, 2, 3, 116, 119, 111, 1, 3, 111, 110, 101]; 22 | /// 23 | /// let map: HashMap>; 24 | /// (map, _) = bincode::serde::decode_from_slice( 25 | /// &example_data, 26 | /// bincode::config::standard(), 27 | /// )?; 28 | /// 29 | /// println!("{:?}", map); 30 | /// 31 | /// Ok(()) 32 | /// } 33 | /// # 34 | /// # fn main() { 35 | /// # deserialize_bytearrays().unwrap(); 36 | /// # } 37 | /// ``` 38 | #[derive(Copy, Clone, Eq, Ord)] 39 | #[repr(transparent)] 40 | pub struct ByteArray { 41 | bytes: [u8; N], 42 | } 43 | 44 | impl ByteArray { 45 | /// Wrap an existing [array] into a `ByteArray`. 46 | pub const fn new(bytes: [u8; N]) -> Self { 47 | ByteArray { bytes } 48 | } 49 | 50 | /// Unwrap the byte array underlying this `ByteArray`. 51 | pub const fn into_array(self) -> [u8; N] { 52 | self.bytes 53 | } 54 | 55 | fn from_ref(bytes: &[u8; N]) -> &Self { 56 | unsafe { &*ptr::addr_of!(*bytes).cast::>() } 57 | } 58 | } 59 | 60 | impl Debug for ByteArray { 61 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 62 | Debug::fmt(&self.bytes, f) 63 | } 64 | } 65 | 66 | impl Default for ByteArray { 67 | fn default() -> Self { 68 | ByteArray { bytes: [0; N] } 69 | } 70 | } 71 | 72 | impl AsRef<[u8; N]> for ByteArray { 73 | fn as_ref(&self) -> &[u8; N] { 74 | &self.bytes 75 | } 76 | } 77 | 78 | impl AsMut<[u8; N]> for ByteArray { 79 | fn as_mut(&mut self) -> &mut [u8; N] { 80 | &mut self.bytes 81 | } 82 | } 83 | 84 | impl Borrow<[u8; N]> for ByteArray { 85 | fn borrow(&self) -> &[u8; N] { 86 | &self.bytes 87 | } 88 | } 89 | 90 | impl BorrowMut<[u8; N]> for ByteArray { 91 | fn borrow_mut(&mut self) -> &mut [u8; N] { 92 | &mut self.bytes 93 | } 94 | } 95 | 96 | impl Deref for ByteArray { 97 | type Target = [u8; N]; 98 | 99 | fn deref(&self) -> &Self::Target { 100 | &self.bytes 101 | } 102 | } 103 | 104 | impl DerefMut for ByteArray { 105 | fn deref_mut(&mut self) -> &mut Self::Target { 106 | &mut self.bytes 107 | } 108 | } 109 | 110 | impl Borrow for ByteArray { 111 | fn borrow(&self) -> &Bytes { 112 | Bytes::new(&self.bytes) 113 | } 114 | } 115 | 116 | impl BorrowMut for ByteArray { 117 | fn borrow_mut(&mut self) -> &mut Bytes { 118 | unsafe { &mut *(&mut self.bytes as &mut [u8] as *mut [u8] as *mut Bytes) } 119 | } 120 | } 121 | 122 | impl From<[u8; N]> for ByteArray { 123 | fn from(bytes: [u8; N]) -> Self { 124 | ByteArray { bytes } 125 | } 126 | } 127 | 128 | impl PartialEq for ByteArray 129 | where 130 | Rhs: ?Sized + Borrow<[u8; N]>, 131 | { 132 | fn eq(&self, other: &Rhs) -> bool { 133 | self.as_ref().eq(other.borrow()) 134 | } 135 | } 136 | 137 | impl PartialOrd for ByteArray 138 | where 139 | Rhs: ?Sized + Borrow<[u8; N]>, 140 | { 141 | fn partial_cmp(&self, other: &Rhs) -> Option { 142 | self.as_ref().partial_cmp(other.borrow()) 143 | } 144 | } 145 | 146 | impl Hash for ByteArray { 147 | fn hash(&self, state: &mut H) { 148 | self.bytes.hash(state); 149 | } 150 | } 151 | 152 | impl IntoIterator for ByteArray { 153 | type Item = u8; 154 | type IntoIter = <[u8; N] as IntoIterator>::IntoIter; 155 | 156 | fn into_iter(self) -> Self::IntoIter { 157 | IntoIterator::into_iter(self.bytes) 158 | } 159 | } 160 | 161 | impl<'a, const N: usize> IntoIterator for &'a ByteArray { 162 | type Item = &'a u8; 163 | type IntoIter = <&'a [u8; N] as IntoIterator>::IntoIter; 164 | 165 | fn into_iter(self) -> Self::IntoIter { 166 | self.bytes.iter() 167 | } 168 | } 169 | 170 | impl<'a, const N: usize> IntoIterator for &'a mut ByteArray { 171 | type Item = &'a mut u8; 172 | type IntoIter = <&'a mut [u8; N] as IntoIterator>::IntoIter; 173 | 174 | fn into_iter(self) -> Self::IntoIter { 175 | self.bytes.iter_mut() 176 | } 177 | } 178 | 179 | impl Serialize for ByteArray { 180 | fn serialize(&self, serializer: S) -> Result 181 | where 182 | S: Serializer, 183 | { 184 | serializer.serialize_bytes(&self.bytes) 185 | } 186 | } 187 | 188 | struct ByteArrayVisitor; 189 | 190 | impl<'de, const N: usize> Visitor<'de> for ByteArrayVisitor { 191 | type Value = ByteArray; 192 | 193 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 194 | write!(formatter, "a byte array of length {N}") 195 | } 196 | 197 | fn visit_seq(self, mut seq: V) -> Result, V::Error> 198 | where 199 | V: SeqAccess<'de>, 200 | { 201 | let mut bytes = [0; N]; 202 | 203 | for (idx, byte) in bytes.iter_mut().enumerate() { 204 | *byte = seq 205 | .next_element()? 206 | .ok_or_else(|| V::Error::invalid_length(idx, &self))?; 207 | } 208 | 209 | Ok(ByteArray::new(bytes)) 210 | } 211 | 212 | fn visit_bytes(self, v: &[u8]) -> Result, E> 213 | where 214 | E: Error, 215 | { 216 | Ok(ByteArray { 217 | bytes: v 218 | .try_into() 219 | .map_err(|_| E::invalid_length(v.len(), &self))?, 220 | }) 221 | } 222 | 223 | fn visit_str(self, v: &str) -> Result, E> 224 | where 225 | E: Error, 226 | { 227 | self.visit_bytes(v.as_bytes()) 228 | } 229 | } 230 | 231 | impl<'de, const N: usize> Deserialize<'de> for ByteArray { 232 | fn deserialize(deserializer: D) -> Result, D::Error> 233 | where 234 | D: Deserializer<'de>, 235 | { 236 | deserializer.deserialize_bytes(ByteArrayVisitor::) 237 | } 238 | } 239 | 240 | struct BorrowedByteArrayVisitor; 241 | 242 | impl<'de, const N: usize> Visitor<'de> for BorrowedByteArrayVisitor { 243 | type Value = &'de ByteArray; 244 | 245 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 246 | write!(formatter, "a borrowed byte array of length {N}") 247 | } 248 | 249 | fn visit_borrowed_bytes(self, v: &'de [u8]) -> Result 250 | where 251 | E: Error, 252 | { 253 | let borrowed_byte_array: &'de [u8; N] = v 254 | .try_into() 255 | .map_err(|_| E::invalid_length(v.len(), &self))?; 256 | Ok(ByteArray::from_ref(borrowed_byte_array)) 257 | } 258 | 259 | fn visit_borrowed_str(self, v: &'de str) -> Result 260 | where 261 | E: Error, 262 | { 263 | self.visit_borrowed_bytes(v.as_bytes()) 264 | } 265 | } 266 | 267 | impl<'a, 'de: 'a, const N: usize> Deserialize<'de> for &'a ByteArray { 268 | fn deserialize(deserializer: D) -> Result 269 | where 270 | D: Deserializer<'de>, 271 | { 272 | deserializer.deserialize_bytes(BorrowedByteArrayVisitor::) 273 | } 274 | } 275 | -------------------------------------------------------------------------------- /src/de.rs: -------------------------------------------------------------------------------- 1 | use crate::{ByteArray, Bytes}; 2 | use core::fmt; 3 | use core::marker::PhantomData; 4 | use serde::de::{Error, Visitor}; 5 | use serde::Deserializer; 6 | 7 | #[cfg(any(feature = "std", feature = "alloc"))] 8 | use crate::ByteBuf; 9 | 10 | #[cfg(any(feature = "std", feature = "alloc"))] 11 | use core::cmp; 12 | 13 | #[cfg(feature = "alloc")] 14 | use alloc::borrow::Cow; 15 | #[cfg(all(feature = "std", not(feature = "alloc")))] 16 | use std::borrow::Cow; 17 | 18 | #[cfg(feature = "alloc")] 19 | use alloc::boxed::Box; 20 | #[cfg(feature = "alloc")] 21 | use alloc::string::String; 22 | #[cfg(feature = "alloc")] 23 | use alloc::vec::Vec; 24 | 25 | #[cfg(any(feature = "std", feature = "alloc"))] 26 | use serde::de::SeqAccess; 27 | 28 | /// Types that can be deserialized via `#[serde(with = "serde_bytes")]`. 29 | pub trait Deserialize<'de>: Sized { 30 | #[allow(missing_docs)] 31 | fn deserialize(deserializer: D) -> Result 32 | where 33 | D: Deserializer<'de>; 34 | } 35 | 36 | impl<'de: 'a, 'a> Deserialize<'de> for &'a [u8] { 37 | fn deserialize(deserializer: D) -> Result 38 | where 39 | D: Deserializer<'de>, 40 | { 41 | // serde::Deserialize for &[u8] is already optimized, so simply forward to that. 42 | serde::Deserialize::deserialize(deserializer) 43 | } 44 | } 45 | 46 | #[cfg(any(feature = "std", feature = "alloc"))] 47 | impl<'de> Deserialize<'de> for Vec { 48 | fn deserialize(deserializer: D) -> Result 49 | where 50 | D: Deserializer<'de>, 51 | { 52 | Deserialize::deserialize(deserializer).map(ByteBuf::into_vec) 53 | } 54 | } 55 | 56 | impl<'de: 'a, 'a> Deserialize<'de> for &'a Bytes { 57 | fn deserialize(deserializer: D) -> Result 58 | where 59 | D: Deserializer<'de>, 60 | { 61 | // serde::Deserialize for &[u8] is already optimized, so simply forward to that. 62 | serde::Deserialize::deserialize(deserializer).map(Bytes::new) 63 | } 64 | } 65 | 66 | impl<'de, const N: usize> Deserialize<'de> for [u8; N] { 67 | fn deserialize(deserializer: D) -> Result 68 | where 69 | D: Deserializer<'de>, 70 | { 71 | let arr: ByteArray = serde::Deserialize::deserialize(deserializer)?; 72 | Ok(*arr) 73 | } 74 | } 75 | 76 | impl<'de, const N: usize> Deserialize<'de> for &'de [u8; N] { 77 | fn deserialize(deserializer: D) -> Result 78 | where 79 | D: Deserializer<'de>, 80 | { 81 | let arr: &ByteArray = serde::Deserialize::deserialize(deserializer)?; 82 | Ok(arr) 83 | } 84 | } 85 | 86 | impl<'de, const N: usize> Deserialize<'de> for ByteArray { 87 | fn deserialize(deserializer: D) -> Result 88 | where 89 | D: Deserializer<'de>, 90 | { 91 | // Via the serde::Deserialize impl for ByteArray. 92 | serde::Deserialize::deserialize(deserializer) 93 | } 94 | } 95 | 96 | impl<'de: 'a, 'a, const N: usize> Deserialize<'de> for &'a ByteArray { 97 | fn deserialize(deserializer: D) -> Result 98 | where 99 | D: Deserializer<'de>, 100 | { 101 | // Via the serde::Deserialize impl for &ByteArray. 102 | serde::Deserialize::deserialize(deserializer) 103 | } 104 | } 105 | 106 | #[cfg(any(feature = "std", feature = "alloc"))] 107 | impl<'de> Deserialize<'de> for ByteBuf { 108 | fn deserialize(deserializer: D) -> Result 109 | where 110 | D: Deserializer<'de>, 111 | { 112 | // Via the serde::Deserialize impl for ByteBuf. 113 | serde::Deserialize::deserialize(deserializer) 114 | } 115 | } 116 | 117 | #[cfg(any(feature = "std", feature = "alloc"))] 118 | impl<'de: 'a, 'a> Deserialize<'de> for Cow<'a, [u8]> { 119 | fn deserialize(deserializer: D) -> Result 120 | where 121 | D: Deserializer<'de>, 122 | { 123 | struct CowVisitor; 124 | 125 | impl<'de> Visitor<'de> for CowVisitor { 126 | type Value = Cow<'de, [u8]>; 127 | 128 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 129 | formatter.write_str("a byte array") 130 | } 131 | 132 | fn visit_borrowed_bytes(self, v: &'de [u8]) -> Result 133 | where 134 | E: Error, 135 | { 136 | Ok(Cow::Borrowed(v)) 137 | } 138 | 139 | fn visit_borrowed_str(self, v: &'de str) -> Result 140 | where 141 | E: Error, 142 | { 143 | Ok(Cow::Borrowed(v.as_bytes())) 144 | } 145 | 146 | fn visit_bytes(self, v: &[u8]) -> Result 147 | where 148 | E: Error, 149 | { 150 | Ok(Cow::Owned(v.to_vec())) 151 | } 152 | 153 | fn visit_str(self, v: &str) -> Result 154 | where 155 | E: Error, 156 | { 157 | Ok(Cow::Owned(v.as_bytes().to_vec())) 158 | } 159 | 160 | fn visit_byte_buf(self, v: Vec) -> Result 161 | where 162 | E: Error, 163 | { 164 | Ok(Cow::Owned(v)) 165 | } 166 | 167 | fn visit_string(self, v: String) -> Result 168 | where 169 | E: Error, 170 | { 171 | Ok(Cow::Owned(v.into_bytes())) 172 | } 173 | 174 | fn visit_seq(self, mut visitor: V) -> Result 175 | where 176 | V: SeqAccess<'de>, 177 | { 178 | let len = cmp::min(visitor.size_hint().unwrap_or(0), 4096); 179 | let mut bytes = Vec::with_capacity(len); 180 | 181 | while let Some(b) = visitor.next_element()? { 182 | bytes.push(b); 183 | } 184 | 185 | Ok(Cow::Owned(bytes)) 186 | } 187 | } 188 | 189 | deserializer.deserialize_bytes(CowVisitor) 190 | } 191 | } 192 | 193 | #[cfg(any(feature = "std", feature = "alloc"))] 194 | impl<'de: 'a, 'a> Deserialize<'de> for Cow<'a, Bytes> { 195 | fn deserialize(deserializer: D) -> Result 196 | where 197 | D: Deserializer<'de>, 198 | { 199 | let cow: Cow<[u8]> = Deserialize::deserialize(deserializer)?; 200 | match cow { 201 | Cow::Borrowed(bytes) => Ok(Cow::Borrowed(Bytes::new(bytes))), 202 | Cow::Owned(bytes) => Ok(Cow::Owned(ByteBuf::from(bytes))), 203 | } 204 | } 205 | } 206 | 207 | #[cfg(any(feature = "std", feature = "alloc"))] 208 | impl<'de> Deserialize<'de> for Box<[u8]> { 209 | fn deserialize(deserializer: D) -> Result 210 | where 211 | D: Deserializer<'de>, 212 | { 213 | Deserialize::deserialize(deserializer).map(Vec::into_boxed_slice) 214 | } 215 | } 216 | 217 | #[cfg(any(feature = "std", feature = "alloc"))] 218 | impl<'de> Deserialize<'de> for Box { 219 | fn deserialize(deserializer: D) -> Result 220 | where 221 | D: Deserializer<'de>, 222 | { 223 | let bytes: Box<[u8]> = Deserialize::deserialize(deserializer)?; 224 | Ok(bytes.into()) 225 | } 226 | } 227 | 228 | impl<'de, T> Deserialize<'de> for Option 229 | where 230 | T: Deserialize<'de>, 231 | { 232 | fn deserialize(deserializer: D) -> Result 233 | where 234 | D: Deserializer<'de>, 235 | { 236 | struct BytesVisitor { 237 | out: PhantomData, 238 | } 239 | 240 | impl<'de, T> Visitor<'de> for BytesVisitor 241 | where 242 | T: Deserialize<'de>, 243 | { 244 | type Value = Option; 245 | 246 | fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { 247 | f.write_str("optional byte array") 248 | } 249 | 250 | fn visit_unit(self) -> Result { 251 | Ok(None) 252 | } 253 | 254 | fn visit_none(self) -> Result { 255 | Ok(None) 256 | } 257 | 258 | fn visit_some(self, deserializer: D) -> Result 259 | where 260 | D: Deserializer<'de>, 261 | { 262 | T::deserialize(deserializer).map(Some) 263 | } 264 | } 265 | 266 | let visitor = BytesVisitor { out: PhantomData }; 267 | deserializer.deserialize_option(visitor) 268 | } 269 | } 270 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | --------------------------------------------------------------------------------