Reverted 'static constraint on T in Vec<T> and [T; N] (#663)

This commit is contained in:
Trangar 2023-09-19 14:58:49 +02:00 committed by GitHub
parent 0d7e7950cb
commit 70fefd6dcc
3 changed files with 77 additions and 52 deletions

View File

@ -8,7 +8,6 @@ use crate::{
impl_borrow_decode, impl_borrow_decode,
}; };
use core::{ use core::{
any::TypeId,
cell::{Cell, RefCell}, cell::{Cell, RefCell},
num::{ num::{
NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
@ -442,63 +441,65 @@ 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 + 'static, T: Decode + Sized,
{ {
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]>())?;
// Optimize for `[u8; N]` // TODO: we can't limit `T: 'static` because that would break other things
if TypeId::of::<u8>() == TypeId::of::<T>() { // 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>());
T::decode(decoder) T::decode(decoder)
})); }));
// result is only None if N does not match the values of `(0..N)`, which it always should // result is only None if N does not match the values of `(0..N)`, which it always should
// So this unwrap should never occur // So this unwrap should never occur
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 + 'static, T: BorrowDecode<'de> + Sized,
{ {
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]>())?;
// Optimize for `[u8; N]` // TODO: we can't limit `T: 'static` because that would break other things
if TypeId::of::<u8>() == TypeId::of::<T>() { // 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>());
T::borrow_decode(decoder) T::borrow_decode(decoder)
})); }));
// result is only None if N does not match the values of `(0..N)`, which it always should // result is only None if N does not match the values of `(0..N)`, which it always should
// So this unwrap should never occur // So this unwrap should never occur
result.unwrap() result.unwrap()
}
} }
} }

View File

@ -1,5 +1,5 @@
use crate::{ use crate::{
de::{read::Reader, BorrowDecoder, Decode, Decoder}, de::{BorrowDecoder, Decode, Decoder},
enc::{ enc::{
self, self,
write::{SizeWriter, Writer}, write::{SizeWriter, Writer},
@ -278,20 +278,23 @@ where
impl<T> Decode for Vec<T> impl<T> Decode for Vec<T>
where where
T: Decode + 'static, 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)?; let len = crate::de::decode_slice_len(decoder)?;
if core::any::TypeId::of::<T>() == core::any::TypeId::of::<u8>() { // TODO: we can't limit `T: 'static` because that would break other things
decoder.claim_container_read::<T>(len)?; // but we want to have this optimization
// optimize for reading u8 vecs // This will be another contendor for specialization implementation
let mut vec = Vec::new(); // if core::any::TypeId::of::<T>() == core::any::TypeId::of::<u8>() {
vec.resize(len, 0u8); // decoder.claim_container_read::<T>(len)?;
decoder.reader().read(&mut vec)?; // // optimize for reading u8 vecs
// Safety: Vec<T> is Vec<u8> // let mut vec = Vec::new();
return Ok(unsafe { core::mem::transmute(vec) }); // vec.resize(len, 0u8);
} // decoder.reader().read(&mut vec)?;
// // 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);

View File

@ -179,3 +179,24 @@ impl std::hash::Hasher for ExampleCustomHasher {
self.hash self.hash
} }
} }
#[test]
fn test_decode_borrow_str_in_array() {
let (strs, _): (Vec<&str>, usize) = bincode::borrow_decode_from_slice(
&[
3, 3, b'a', b'b', b'c', 3, b'd', b'e', b'f', 3, b'g', b'h', b'i',
],
bincode::config::standard(),
)
.unwrap();
assert_eq!(strs, vec!["abc", "def", "ghi"]);
let (strs, _): ([&str; 3], usize) = bincode::borrow_decode_from_slice(
&[
3, b'a', b'b', b'c', 3, b'd', b'e', b'f', 3, b'g', b'h', b'i',
],
bincode::config::standard(),
)
.unwrap();
assert_eq!(strs, ["abc", "def", "ghi"]);
}