Skip to main content

ab_core_primitives/pieces/
piece.rs

1#[cfg(all(test, feature = "serde"))]
2mod tests;
3
4use crate::pieces::InnerPiece;
5use crate::pieces::cow_bytes::CowBytes;
6use ab_io_type::trivial_type::TrivialType;
7#[cfg(any(feature = "scale-codec", feature = "serde"))]
8use alloc::format;
9use alloc::vec::Vec;
10use bytes::{Bytes, BytesMut};
11use core::ops::{Deref, DerefMut};
12#[cfg(feature = "scale-codec")]
13use parity_scale_codec::{Decode, Encode, EncodeLike, Input, Output};
14#[cfg(feature = "serde")]
15use serde::{Deserialize, Deserializer, Serialize, Serializer};
16
17/// A piece of archival history.
18///
19/// This version is allocated on the heap, for stack-allocated piece see [`InnerPiece`].
20///
21/// Internally piece contains a record and corresponding proof that together with segment
22/// root of the segment this piece belongs to can be used to verify that a piece belongs to
23/// the actual archival history of the blockchain.
24#[derive(Debug, Clone, PartialEq, Eq, Hash)]
25pub struct Piece(pub(super) CowBytes);
26
27#[cfg(feature = "scale-codec")]
28impl Encode for Piece {
29    #[inline]
30    fn size_hint(&self) -> usize {
31        self.as_ref().size_hint()
32    }
33
34    #[inline]
35    fn encode_to<O>(&self, dest: &mut O)
36    where
37        O: Output + ?Sized,
38    {
39        self.as_ref().encode_to(dest);
40    }
41
42    #[inline]
43    fn encode(&self) -> Vec<u8> {
44        self.as_ref().encode()
45    }
46
47    #[inline]
48    fn using_encoded<R, F>(&self, f: F) -> R
49    where
50        F: FnOnce(&[u8]) -> R,
51    {
52        self.as_ref().using_encoded(f)
53    }
54}
55
56#[cfg(feature = "scale-codec")]
57impl EncodeLike for Piece {}
58
59#[cfg(feature = "scale-codec")]
60impl Decode for Piece {
61    fn decode<I>(input: &mut I) -> Result<Self, parity_scale_codec::Error>
62    where
63        I: Input,
64    {
65        let bytes =
66            Bytes::decode(input).map_err(|error| error.chain("Could not decode `Piece`"))?;
67
68        if bytes.len() != Self::SIZE {
69            return Err(
70                parity_scale_codec::Error::from("Incorrect Piece length").chain(format!(
71                    "Expected {} bytes, found {} bytes",
72                    Self::SIZE,
73                    bytes.len()
74                )),
75            );
76        }
77
78        Ok(Piece(CowBytes::Shared(bytes)))
79    }
80}
81
82#[cfg(feature = "serde")]
83impl Serialize for Piece {
84    #[inline]
85    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
86    where
87        S: Serializer,
88    {
89        let bytes = match &self.0 {
90            CowBytes::Shared(bytes) => bytes.as_ref(),
91            CowBytes::Owned(bytes) => bytes.as_ref(),
92        };
93
94        if serializer.is_human_readable() {
95            hex::serde::serialize(bytes, serializer)
96        } else {
97            bytes.serialize(serializer)
98        }
99    }
100}
101
102#[cfg(feature = "serde")]
103impl<'de> Deserialize<'de> for Piece {
104    #[inline]
105    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
106    where
107        D: Deserializer<'de>,
108    {
109        let bytes = if deserializer.is_human_readable() {
110            Bytes::from(hex::serde::deserialize::<_, Vec<u8>>(deserializer)?)
111        } else {
112            Bytes::deserialize(deserializer)?
113        };
114        let length = bytes.len();
115
116        Piece::try_from(bytes).map_err(|()| {
117            serde::de::Error::invalid_length(
118                length,
119                &format!("Expected {} bytes", Piece::SIZE).as_str(),
120            )
121        })
122    }
123}
124
125impl Default for Piece {
126    #[inline]
127    fn default() -> Self {
128        Self(CowBytes::Owned(BytesMut::zeroed(Self::SIZE)))
129    }
130}
131
132impl From<Piece> for Vec<u8> {
133    #[inline]
134    fn from(piece: Piece) -> Self {
135        match piece.0 {
136            CowBytes::Shared(bytes) => bytes.to_vec(),
137            CowBytes::Owned(bytes) => Vec::from(bytes),
138        }
139    }
140}
141
142impl TryFrom<&[u8]> for Piece {
143    type Error = ();
144
145    #[inline]
146    fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
147        if slice.len() != Self::SIZE {
148            return Err(());
149        }
150
151        Ok(Self(CowBytes::Shared(Bytes::copy_from_slice(slice))))
152    }
153}
154
155impl TryFrom<Vec<u8>> for Piece {
156    type Error = ();
157
158    #[inline]
159    fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
160        if vec.len() != Self::SIZE {
161            return Err(());
162        }
163
164        Ok(Self(CowBytes::Shared(Bytes::from(vec))))
165    }
166}
167
168impl TryFrom<Bytes> for Piece {
169    type Error = ();
170
171    #[inline]
172    fn try_from(bytes: Bytes) -> Result<Self, Self::Error> {
173        if bytes.len() != Self::SIZE {
174            return Err(());
175        }
176
177        Ok(Self(CowBytes::Shared(bytes)))
178    }
179}
180
181impl TryFrom<BytesMut> for Piece {
182    type Error = ();
183
184    #[inline]
185    fn try_from(bytes: BytesMut) -> Result<Self, Self::Error> {
186        if bytes.len() != Self::SIZE {
187            return Err(());
188        }
189
190        Ok(Self(CowBytes::Owned(bytes)))
191    }
192}
193
194impl From<&InnerPiece> for Piece {
195    #[inline]
196    fn from(value: &InnerPiece) -> Self {
197        Self(CowBytes::Shared(Bytes::copy_from_slice(value.as_bytes())))
198    }
199}
200
201impl Deref for Piece {
202    type Target = InnerPiece;
203
204    #[inline]
205    fn deref(&self) -> &Self::Target {
206        // SAFETY: Correct size and alignment
207        unsafe { InnerPiece::from_bytes_unchecked(self.as_ref()) }
208    }
209}
210
211impl DerefMut for Piece {
212    #[inline]
213    fn deref_mut(&mut self) -> &mut Self::Target {
214        // SAFETY: Correct size and alignment
215        unsafe { InnerPiece::from_bytes_mut_unchecked(self.as_mut()) }
216    }
217}
218
219impl AsRef<[u8]> for Piece {
220    #[inline]
221    fn as_ref(&self) -> &[u8] {
222        self.0.as_ref()
223    }
224}
225
226impl AsMut<[u8]> for Piece {
227    #[inline]
228    fn as_mut(&mut self) -> &mut [u8] {
229        self.0.as_mut()
230    }
231}
232
233impl Piece {
234    /// Size of a piece (in bytes)
235    pub const SIZE: usize = InnerPiece::SIZE;
236
237    /// Ensure piece contains cheaply cloneable shared data.
238    ///
239    /// Internally piece uses CoW mechanism and can store either mutable owned data or data that is
240    /// cheap to clone, calling this method will ensure further clones will not result in additional
241    /// memory allocations.
242    pub fn to_shared(self) -> Self {
243        Self(match self.0 {
244            CowBytes::Shared(bytes) => CowBytes::Shared(bytes),
245            CowBytes::Owned(bytes) => CowBytes::Shared(bytes.freeze()),
246        })
247    }
248}