Git Product home page Git Product logo

Comments (2)

preston-evans98 avatar preston-evans98 commented on July 18, 2024

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.

frol avatar frol commented on July 18, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.