ab_core_primitives/pieces/
piece.rs

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