Skip to main content

ab_core_primitives/pieces/
piece.rs

1use crate::pieces::InnerPiece;
2use crate::pieces::cow_bytes::CowBytes;
3use ab_io_type::trivial_type::TrivialType;
4#[cfg(any(feature = "scale-codec", feature = "serde"))]
5use alloc::format;
6use alloc::vec::Vec;
7use bytes::{Bytes, BytesMut};
8use core::ops::{Deref, DerefMut};
9#[cfg(feature = "scale-codec")]
10use parity_scale_codec::{Decode, Encode, EncodeLike, Input, Output};
11#[cfg(feature = "serde")]
12use serde::{Deserialize, Deserializer, Serialize, Serializer};
13
14/// A piece of archival history.
15///
16/// This version is allocated on the heap, for stack-allocated piece see [`InnerPiece`].
17///
18/// Internally piece contains a record and corresponding proof that together with segment
19/// root of the segment this piece belongs to can be used to verify that a piece belongs to
20/// the actual archival history of the blockchain.
21#[derive(Debug, Clone, PartialEq, Eq, Hash)]
22pub struct Piece(pub(super) CowBytes);
23
24#[cfg(feature = "scale-codec")]
25impl Encode for Piece {
26    #[inline]
27    fn size_hint(&self) -> usize {
28        self.as_ref().size_hint()
29    }
30
31    #[inline]
32    fn encode_to<O>(&self, dest: &mut O)
33    where
34        O: Output + ?Sized,
35    {
36        self.as_ref().encode_to(dest);
37    }
38
39    #[inline]
40    fn encode(&self) -> Vec<u8> {
41        self.as_ref().encode()
42    }
43
44    #[inline]
45    fn using_encoded<R, F>(&self, f: F) -> R
46    where
47        F: FnOnce(&[u8]) -> R,
48    {
49        self.as_ref().using_encoded(f)
50    }
51}
52
53#[cfg(feature = "scale-codec")]
54impl EncodeLike for Piece {}
55
56#[cfg(feature = "scale-codec")]
57impl Decode for Piece {
58    fn decode<I>(input: &mut I) -> Result<Self, parity_scale_codec::Error>
59    where
60        I: Input,
61    {
62        let bytes =
63            Bytes::decode(input).map_err(|error| error.chain("Could not decode `Piece`"))?;
64
65        if bytes.len() != Self::SIZE {
66            return Err(
67                parity_scale_codec::Error::from("Incorrect Piece length").chain(format!(
68                    "Expected {} bytes, found {} bytes",
69                    Self::SIZE,
70                    bytes.len()
71                )),
72            );
73        }
74
75        Ok(Piece(CowBytes::Shared(bytes)))
76    }
77}
78
79#[cfg(feature = "serde")]
80impl Serialize for Piece {
81    #[inline]
82    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
83    where
84        S: Serializer,
85    {
86        let bytes = match &self.0 {
87            CowBytes::Shared(bytes) => bytes.as_ref(),
88            CowBytes::Owned(bytes) => bytes.as_ref(),
89        };
90
91        if serializer.is_human_readable() {
92            hex::serde::serialize(bytes, serializer)
93        } else {
94            bytes.serialize(serializer)
95        }
96    }
97}
98
99#[cfg(feature = "serde")]
100impl<'de> Deserialize<'de> for Piece {
101    #[inline]
102    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
103    where
104        D: Deserializer<'de>,
105    {
106        let bytes = if deserializer.is_human_readable() {
107            hex::serde::deserialize::<_, Vec<u8>>(deserializer).and_then(|bytes| {
108                if bytes.len() == Piece::SIZE {
109                    Ok(Bytes::from(bytes))
110                } else {
111                    Err(serde::de::Error::invalid_length(
112                        bytes.len(),
113                        &format!("Expected {} bytes", Piece::SIZE).as_str(),
114                    ))
115                }
116            })?
117        } else {
118            Bytes::deserialize(deserializer)?
119        };
120
121        Ok(Piece(CowBytes::Shared(bytes)))
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}