Added unty dependency and added type checks (#667)

* Added unty dependency and added type checks

* Bumped unty 0.0.2

* Bump unty to 0.0.3

* Removed unneeded + Sized requirements
Optimize encode for [T; N]
Made BinaryHeap<T> proxy to Vec<T>
Made VecDeque decode/borrowdecode proxy to Vec<T>
Optimize VecDeque::<u8>::Encode to write 2 slices directly
Optimize Vec<u8> borrowdecode implementation

---------

Co-authored-by: Victor Koenders <git@trang.ar>
This commit is contained in:
Trangar 2023-09-28 17:32:11 +02:00 committed by GitHub
parent feae25878a
commit e03c9b06db
4 changed files with 190 additions and 228 deletions

View File

@ -33,6 +33,7 @@ derive = ["bincode_derive"]
[dependencies] [dependencies]
bincode_derive = { path = "derive", version = "2.0.0-rc.3", optional = true } bincode_derive = { path = "derive", version = "2.0.0-rc.3", optional = true }
serde = { version = "1.0", default-features = false, optional = true } serde = { version = "1.0", default-features = false, optional = true }
unty = "0.0.3"
# Used for tests # Used for tests
[dev-dependencies] [dev-dependencies]

View File

@ -441,24 +441,21 @@ impl<'a, 'de: 'a> BorrowDecode<'de> for &'a str {
impl<T, const N: usize> Decode for [T; N] impl<T, const N: usize> Decode for [T; N]
where where
T: Decode + Sized, T: Decode,
{ {
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> { fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
decoder.claim_bytes_read(core::mem::size_of::<[T; N]>())?; decoder.claim_bytes_read(core::mem::size_of::<[T; N]>())?;
// TODO: we can't limit `T: 'static` because that would break other things if unty::type_equal::<T, u8>() {
// but we want to have this optimization let mut buf = [0u8; N];
// This will be another contendor for specialization implementation decoder.reader().read(&mut buf)?;
// if TypeId::of::<u8>() == TypeId::of::<T>() { let ptr = &mut buf as *mut _ as *mut [T; N];
// let mut buf = [0u8; N];
// decoder.reader().read(&mut buf)?;
// let ptr = &mut buf as *mut _ as *mut [T; N];
// // Safety: we know that T is a u8, so it is perfectly safe to // Safety: we know that T is a u8, so it is perfectly safe to
// // translate an array of u8 into an array of T // translate an array of u8 into an array of T
// let res = unsafe { ptr.read() }; let res = unsafe { ptr.read() };
// Ok(res) Ok(res)
// } } else {
let result = super::impl_core::collect_into_array(&mut (0..N).map(|_| { let result = super::impl_core::collect_into_array(&mut (0..N).map(|_| {
// See the documentation on `unclaim_bytes_read` as to why we're doing this here // See the documentation on `unclaim_bytes_read` as to why we're doing this here
decoder.unclaim_bytes_read(core::mem::size_of::<T>()); decoder.unclaim_bytes_read(core::mem::size_of::<T>());
@ -470,27 +467,25 @@ where
result.unwrap() result.unwrap()
} }
} }
}
impl<'de, T, const N: usize> BorrowDecode<'de> for [T; N] impl<'de, T, const N: usize> BorrowDecode<'de> for [T; N]
where where
T: BorrowDecode<'de> + Sized, T: BorrowDecode<'de>,
{ {
fn borrow_decode<D: BorrowDecoder<'de>>(decoder: &mut D) -> Result<Self, DecodeError> { fn borrow_decode<D: BorrowDecoder<'de>>(decoder: &mut D) -> Result<Self, DecodeError> {
decoder.claim_bytes_read(core::mem::size_of::<[T; N]>())?; decoder.claim_bytes_read(core::mem::size_of::<[T; N]>())?;
// TODO: we can't limit `T: 'static` because that would break other things if unty::type_equal::<T, u8>() {
// but we want to have this optimization let mut buf = [0u8; N];
// This will be another contendor for specialization implementation decoder.reader().read(&mut buf)?;
// if TypeId::of::<u8>() == TypeId::of::<T>() { let ptr = &mut buf as *mut _ as *mut [T; N];
// let mut buf = [0u8; N];
// decoder.reader().read(&mut buf)?;
// let ptr = &mut buf as *mut _ as *mut [T; N];
// // Safety: we know that T is a u8, so it is perfectly safe to // Safety: we know that T is a u8, so it is perfectly safe to
// // translate an array of u8 into an array of T // translate an array of u8 into an array of T
// let res = unsafe { ptr.read() }; let res = unsafe { ptr.read() };
// Ok(res) Ok(res)
// } } else {
let result = super::impl_core::collect_into_array(&mut (0..N).map(|_| { let result = super::impl_core::collect_into_array(&mut (0..N).map(|_| {
// See the documentation on `unclaim_bytes_read` as to why we're doing this here // See the documentation on `unclaim_bytes_read` as to why we're doing this here
decoder.unclaim_bytes_read(core::mem::size_of::<T>()); decoder.unclaim_bytes_read(core::mem::size_of::<T>());
@ -502,6 +497,7 @@ where
result.unwrap() result.unwrap()
} }
} }
}
impl Decode for () { impl Decode for () {
fn decode<D: Decoder>(_: &mut D) -> Result<Self, DecodeError> { fn decode<D: Decoder>(_: &mut D) -> Result<Self, DecodeError> {
@ -547,22 +543,6 @@ where
} }
} }
// BlockedTODO: https://github.com/rust-lang/rust/issues/37653
//
// We'll want to implement BorrowDecode for both Option<&[u8]> and Option<&[T: Encode]>,
// but those implementations overlap because &'a [u8] also implements BorrowDecode
// impl<'a, 'de: 'a> BorrowDecode<'de> for Option<&'a [u8]> {
// fn borrow_decode<D: BorrowDecoder<'de>>(decoder: &mut D) -> Result<Self, DecodeError> {
// match super::decode_option_variant(decoder, core::any::type_name::<Option<&[u8]>>())? {
// Some(_) => {
// let val = BorrowDecode::borrow_decode(decoder)?;
// Ok(Some(val))
// }
// None => Ok(None),
// }
// }
// }
impl<T, U> Decode for Result<T, U> impl<T, U> Decode for Result<T, U>
where where
T: Decode, T: Decode,

View File

@ -280,24 +280,15 @@ impl Encode for char {
} }
} }
// BlockedTODO: https://github.com/rust-lang/rust/issues/37653
//
// We'll want to implement encoding for both &[u8] and &[T: Encode],
// but those implementations overlap because u8 also implements Encode
// impl Encode for &'_ [u8] {
// fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
// encoder.writer().write(*self)
// }
// }
impl<T> Encode for [T] impl<T> Encode for [T]
where where
T: Encode + 'static, T: Encode,
{ {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> { fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
super::encode_slice_len(encoder, self.len())?; super::encode_slice_len(encoder, self.len())?;
if core::any::TypeId::of::<T>() == core::any::TypeId::of::<u8>() { if unty::type_equal::<T, u8>() {
// Safety: T = u8
let t: &[u8] = unsafe { core::mem::transmute(self) }; let t: &[u8] = unsafe { core::mem::transmute(self) };
encoder.writer().write(t)?; encoder.writer().write(t)?;
return Ok(()); return Ok(());
@ -355,12 +346,19 @@ where
T: Encode, T: Encode,
{ {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> { fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
if unty::type_equal::<T, u8>() {
// Safety: this is &[u8; N]
let array_slice: &[u8] =
unsafe { core::slice::from_raw_parts(self.as_ptr().cast(), N) };
encoder.writer().write(array_slice)
} else {
for item in self.iter() { for item in self.iter() {
item.encode(encoder)?; item.encode(encoder)?;
} }
Ok(()) Ok(())
} }
} }
}
impl<T> Encode for Option<T> impl<T> Encode for Option<T>
where where

View File

@ -1,5 +1,5 @@
use crate::{ use crate::{
de::{BorrowDecoder, Decode, Decoder}, de::{read::Reader, BorrowDecoder, Decode, Decoder},
enc::{ enc::{
self, self,
write::{SizeWriter, Writer}, write::{SizeWriter, Writer},
@ -8,8 +8,6 @@ use crate::{
error::{DecodeError, EncodeError}, error::{DecodeError, EncodeError},
impl_borrow_decode, BorrowDecode, Config, impl_borrow_decode, BorrowDecode, Config,
}; };
#[cfg(target_has_atomic = "ptr")]
use alloc::sync::Arc;
use alloc::{ use alloc::{
borrow::{Cow, ToOwned}, borrow::{Cow, ToOwned},
boxed::Box, boxed::Box,
@ -19,6 +17,9 @@ use alloc::{
vec::Vec, vec::Vec,
}; };
#[cfg(target_has_atomic = "ptr")]
use alloc::sync::Arc;
#[derive(Default)] #[derive(Default)]
pub(crate) struct VecWriter { pub(crate) struct VecWriter {
inner: Vec<u8>, inner: Vec<u8>,
@ -67,18 +68,7 @@ where
T: Decode + Ord, T: Decode + Ord,
{ {
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> { fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
let len = crate::de::decode_slice_len(decoder)?; Ok(Vec::<T>::decode(decoder)?.into())
decoder.claim_container_read::<T>(len)?;
let mut map = BinaryHeap::with_capacity(len);
for _ in 0..len {
// See the documentation on `unclaim_bytes_read` as to why we're doing this here
decoder.unclaim_bytes_read(core::mem::size_of::<T>());
let key = T::decode(decoder)?;
map.push(key);
}
Ok(map)
} }
} }
impl<'de, T> BorrowDecode<'de> for BinaryHeap<T> impl<'de, T> BorrowDecode<'de> for BinaryHeap<T>
@ -86,18 +76,7 @@ where
T: BorrowDecode<'de> + Ord, T: BorrowDecode<'de> + Ord,
{ {
fn borrow_decode<D: BorrowDecoder<'de>>(decoder: &mut D) -> Result<Self, DecodeError> { fn borrow_decode<D: BorrowDecoder<'de>>(decoder: &mut D) -> Result<Self, DecodeError> {
let len = crate::de::decode_slice_len(decoder)?; Ok(Vec::<T>::borrow_decode(decoder)?.into())
decoder.claim_container_read::<T>(len)?;
let mut map = BinaryHeap::with_capacity(len);
for _ in 0..len {
// See the documentation on `unclaim_bytes_read` as to why we're doing this here
decoder.unclaim_bytes_read(core::mem::size_of::<T>());
let key = T::borrow_decode(decoder)?;
map.push(key);
}
Ok(map)
} }
} }
@ -106,6 +85,7 @@ where
T: Encode + Ord, T: Encode + Ord,
{ {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> { fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
// BLOCKEDTODO(https://github.com/rust-lang/rust/issues/83659): we can u8 optimize this with `.as_slice()`
crate::enc::encode_slice_len(encoder, self.len())?; crate::enc::encode_slice_len(encoder, self.len())?;
for val in self.iter() { for val in self.iter() {
val.encode(encoder)?; val.encode(encoder)?;
@ -229,18 +209,7 @@ where
T: Decode, T: Decode,
{ {
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> { fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
let len = crate::de::decode_slice_len(decoder)?; Ok(Vec::<T>::decode(decoder)?.into())
decoder.claim_container_read::<T>(len)?;
let mut map = VecDeque::with_capacity(len);
for _ in 0..len {
// See the documentation on `unclaim_bytes_read` as to why we're doing this here
decoder.unclaim_bytes_read(core::mem::size_of::<T>());
let key = T::decode(decoder)?;
map.push_back(key);
}
Ok(map)
} }
} }
impl<'de, T> BorrowDecode<'de> for VecDeque<T> impl<'de, T> BorrowDecode<'de> for VecDeque<T>
@ -248,18 +217,7 @@ where
T: BorrowDecode<'de>, T: BorrowDecode<'de>,
{ {
fn borrow_decode<D: BorrowDecoder<'de>>(decoder: &mut D) -> Result<Self, DecodeError> { fn borrow_decode<D: BorrowDecoder<'de>>(decoder: &mut D) -> Result<Self, DecodeError> {
let len = crate::de::decode_slice_len(decoder)?; Ok(Vec::<T>::borrow_decode(decoder)?.into())
decoder.claim_container_read::<T>(len)?;
let mut map = VecDeque::with_capacity(len);
for _ in 0..len {
// See the documentation on `unclaim_bytes_read` as to why we're doing this here
decoder.unclaim_bytes_read(core::mem::size_of::<T>());
let key = T::borrow_decode(decoder)?;
map.push_back(key);
}
Ok(map)
} }
} }
@ -269,9 +227,23 @@ where
{ {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> { fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
crate::enc::encode_slice_len(encoder, self.len())?; crate::enc::encode_slice_len(encoder, self.len())?;
if unty::type_equal::<T, u8>() {
let slices: (&[T], &[T]) = self.as_slices();
// Safety: T is u8 so turning this into `&[u8]` is okay
let slices: (&[u8], &[u8]) = unsafe {
(
core::slice::from_raw_parts(slices.0.as_ptr().cast(), slices.0.len()),
core::slice::from_raw_parts(slices.1.as_ptr().cast(), slices.1.len()),
)
};
encoder.writer().write(slices.0)?;
encoder.writer().write(slices.1)?;
} else {
for item in self.iter() { for item in self.iter() {
item.encode(encoder)?; item.encode(encoder)?;
} }
}
Ok(()) Ok(())
} }
} }
@ -283,18 +255,15 @@ where
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> { fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
let len = crate::de::decode_slice_len(decoder)?; let len = crate::de::decode_slice_len(decoder)?;
// TODO: we can't limit `T: 'static` because that would break other things if unty::type_equal::<T, u8>() {
// but we want to have this optimization decoder.claim_container_read::<T>(len)?;
// This will be another contendor for specialization implementation // optimize for reading u8 vecs
// if core::any::TypeId::of::<T>() == core::any::TypeId::of::<u8>() { let mut vec = Vec::new();
// decoder.claim_container_read::<T>(len)?; vec.resize(len, 0u8);
// // optimize for reading u8 vecs decoder.reader().read(&mut vec)?;
// let mut vec = Vec::new(); // Safety: Vec<T> is Vec<u8>
// vec.resize(len, 0u8); Ok(unsafe { core::mem::transmute(vec) })
// decoder.reader().read(&mut vec)?; } else {
// // Safety: Vec<T> is Vec<u8>
// return Ok(unsafe { core::mem::transmute(vec) });
// }
decoder.claim_container_read::<T>(len)?; decoder.claim_container_read::<T>(len)?;
let mut vec = Vec::with_capacity(len); let mut vec = Vec::with_capacity(len);
@ -307,6 +276,7 @@ where
Ok(vec) Ok(vec)
} }
} }
}
impl<'de, T> BorrowDecode<'de> for Vec<T> impl<'de, T> BorrowDecode<'de> for Vec<T>
where where
@ -314,6 +284,16 @@ where
{ {
fn borrow_decode<D: BorrowDecoder<'de>>(decoder: &mut D) -> Result<Self, DecodeError> { fn borrow_decode<D: BorrowDecoder<'de>>(decoder: &mut D) -> Result<Self, DecodeError> {
let len = crate::de::decode_slice_len(decoder)?; let len = crate::de::decode_slice_len(decoder)?;
if unty::type_equal::<T, u8>() {
decoder.claim_container_read::<T>(len)?;
// optimize for reading u8 vecs
let mut vec = Vec::new();
vec.resize(len, 0u8);
decoder.reader().read(&mut vec)?;
// Safety: Vec<T> is Vec<u8>
Ok(unsafe { core::mem::transmute(vec) })
} else {
decoder.claim_container_read::<T>(len)?; decoder.claim_container_read::<T>(len)?;
let mut vec = Vec::with_capacity(len); let mut vec = Vec::with_capacity(len);
@ -326,24 +306,27 @@ where
Ok(vec) Ok(vec)
} }
} }
}
impl<T> Encode for Vec<T> impl<T> Encode for Vec<T>
where where
T: Encode + 'static, T: Encode,
{ {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> { fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
crate::enc::encode_slice_len(encoder, self.len())?; crate::enc::encode_slice_len(encoder, self.len())?;
if core::any::TypeId::of::<T>() == core::any::TypeId::of::<u8>() { if unty::type_equal::<T, u8>() {
// Safety: T == u8
let slice: &[u8] = unsafe { core::mem::transmute(self.as_slice()) }; let slice: &[u8] = unsafe { core::mem::transmute(self.as_slice()) };
encoder.writer().write(slice)?; encoder.writer().write(slice)?;
return Ok(()); Ok(())
} } else {
for item in self.iter() { for item in self.iter() {
item.encode(encoder)?; item.encode(encoder)?;
} }
Ok(()) Ok(())
} }
} }
}
impl Decode for String { impl Decode for String {
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> { fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {