Comments (2)
You may have already considered this, but adding an unsafe
marker trait would let us push this decision to the caller and fix the unsoundness in #19
pub mod zst {
/// A marker trait indicating that a zero-sized type can have its deserialization optimized away
pub unsafe trait CanSkipDeserialize: Sized + crate::BorshDeserialize {}
/// A wrapper around Vec<T> for ZSTs that invokes T::deserialize only
/// once regardless of the length of the vector.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SkippableVec<T>(pub Vec<T>);
impl<T: CanSkipDeserialize> From<SkippableVec<T>> for Vec<T> {
fn from(value: SkippableVec<T>) -> Self {
value.0
}
}
/// A marker trait indicating that a type is zero-sized. Panics at compile time
/// if implemented for a non-ZST.
trait IsZst: Sized {
const IS_ZST: () = assert!(core::mem::size_of::<Self>() == 0);
}
/// Prevent people from implementing CanSkipDeserialize for non-ZSTs by blanket
/// implementing the IsZst marker trait.
impl<T: CanSkipDeserialize> IsZst for T {}
}
Until specialization lands, I think users will have to manually replace Vec<T>
with SkippableVec<T>
when they want to opt in to the ZST optimization, though we may be able to use some macro magic to help with derived impls.
impl<T: BorshDeserialize> BorshDeserialize for SkippableVec<T> {
fn deserialize_reader<R: Read>(reader: &mut R) -> Result<Self> {
let len = u32::deserialize_reader(reader)?;
let mut result = vec![T::deserialize_reader(reader)?];
let p = result.as_mut_ptr();
unsafe {
forget(result);
let len = len.try_into().map_err(|_| ErrorKind::InvalidInput)?;
let result = Vec::from_raw_parts(p, len, len);
Ok(Self(result))
}
}
}
impl<T> BorshDeserialize for Vec<T>
where
T: BorshDeserialize,
{
#[inline]
fn deserialize_reader<R: Read>(reader: &mut R) -> Result<Self> {
let len = u32::deserialize_reader(reader)?;
if len == 0 {
Ok(Vec::new())
} else if let Some(vec_bytes) = T::vec_from_reader(len, reader)? {
Ok(vec_bytes)
} else {
// TODO(16): return capacity allocation when we can safely do that.
let mut result = Vec::with_capacity(hint::cautious::<T>(len));
for _ in 0..len {
result.push(T::deserialize_reader(reader)?);
}
Ok(result)
}
}
}
Once specialization does land, we can just use a specialized deserialize
impl for types that implement the marker trait.
from borsh-rs.
it doesn't' fully address the problem (we have the same issue for hash maps)
I cannot think of hashmap of zero-size keys. Though, a vector of zero-sized types is also pointless in my opinion, so I believe the best thing is to just forbid collections of zero-size elements (#136 (comment)). I am wondering if there is a way to do it through the type system (in the worst case, we will do it at runtime).
from borsh-rs.
Related Issues (20)
- Include discriminant number in `BorshSchema::Enum::variants`
- Rename declarations (tuples, `nil`, `string`, `nonzero_xx` and arrays) HOT 5
- add implementation for `BorshSerialize`, `BorshDeserialize`, `BorshSchema` for `char` HOT 3
- Security Policy violation Branch Protection HOT 2
- Security Policy violation SECURITY.md HOT 2
- Restriction on Serializing Zero-Sized Types Affects Marker Component Usage HOT 7
- derive BoshSerialize fails if the type already uses `W` generic name HOT 4
- BorshSerialize derive fails for structs with packed attribute HOT 4
- Should `std` feature imply `rc` feature and vice-versa? HOT 4
- Read/Write mutable reference in `serialize` and `deserialize_reader` is unnecessary HOT 8
- `derive` macros require `cargo` to be present HOT 4
- Old NEAR contracts won't compile with the new `borsh` re-exported from `near-sdk-rs` ("Could not find `borsh`") HOT 5
- equivalent of `#[serde(default)]` HOT 2
- Borsh 2.0? Not planned HOT 2
- Extract `alloc` feature (2.0 candidate) HOT 1
- `bytes::Bytes` and `bytes::BytesMut` can be complemented with `BorshSchema`
- `bson::oid::ObjectId` can be complemented with `BorshSchema`
- Add struct/enum attr to relax bounds
- feat(schema): for chars HOT 4
- feat(schema): support serde of HashMap with S hasher
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from borsh-rs.