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 = "scale-codec")]
11use scale_info::build::Fields;
12#[cfg(feature = "scale-codec")]
13use scale_info::{Path, Type, TypeInfo};
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 [`PieceArray`].
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: Output + ?Sized>(&self, output: &mut O) {
36        self.as_ref().encode_to(output)
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: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
46        self.as_ref().using_encoded(f)
47    }
48}
49
50#[cfg(feature = "scale-codec")]
51impl EncodeLike for Piece {}
52
53#[cfg(feature = "scale-codec")]
54impl Decode for Piece {
55    fn decode<I: Input>(input: &mut I) -> Result<Self, parity_scale_codec::Error> {
56        let bytes =
57            Bytes::decode(input).map_err(|error| error.chain("Could not decode `Piece`"))?;
58
59        if bytes.len() != Self::SIZE {
60            return Err(
61                parity_scale_codec::Error::from("Incorrect Piece length").chain(format!(
62                    "Expected {} bytes, found {} bytes",
63                    Self::SIZE,
64                    bytes.len()
65                )),
66            );
67        }
68
69        Ok(Piece(CowBytes::Shared(bytes)))
70    }
71}
72
73#[cfg(feature = "scale-codec")]
74impl TypeInfo for Piece {
75    type Identity = Self;
76
77    fn type_info() -> Type {
78        Type::builder()
79            .path(Path::new("Piece", module_path!()))
80            .docs(&["A piece of archival history"])
81            .composite(
82                Fields::unnamed().field(|f| f.ty::<[u8; Piece::SIZE]>().type_name("PieceArray")),
83            )
84    }
85}
86
87#[cfg(feature = "serde")]
88impl Serialize for Piece {
89    #[inline]
90    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
91    where
92        S: Serializer,
93    {
94        let bytes = match &self.0 {
95            CowBytes::Shared(bytes) => bytes.as_ref(),
96            CowBytes::Owned(bytes) => bytes.as_ref(),
97        };
98
99        if serializer.is_human_readable() {
100            hex::serde::serialize(bytes, serializer)
101        } else {
102            bytes.serialize(serializer)
103        }
104    }
105}
106
107#[cfg(feature = "serde")]
108impl<'de> Deserialize<'de> for Piece {
109    #[inline]
110    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
111    where
112        D: Deserializer<'de>,
113    {
114        let bytes = if deserializer.is_human_readable() {
115            hex::serde::deserialize::<_, Vec<u8>>(deserializer).and_then(|bytes| {
116                if bytes.len() == Piece::SIZE {
117                    Ok(Bytes::from(bytes))
118                } else {
119                    Err(serde::de::Error::invalid_length(
120                        bytes.len(),
121                        &format!("Expected {} bytes", Piece::SIZE).as_str(),
122                    ))
123                }
124            })?
125        } else {
126            Bytes::deserialize(deserializer)?
127        };
128
129        Ok(Piece(CowBytes::Shared(bytes)))
130    }
131}
132
133impl Default for Piece {
134    #[inline]
135    fn default() -> Self {
136        Self(CowBytes::Owned(BytesMut::zeroed(Self::SIZE)))
137    }
138}
139
140impl From<Piece> for Vec<u8> {
141    #[inline]
142    fn from(piece: Piece) -> Self {
143        match piece.0 {
144            CowBytes::Shared(bytes) => bytes.to_vec(),
145            CowBytes::Owned(bytes) => Vec::from(bytes),
146        }
147    }
148}
149
150impl TryFrom<&[u8]> for Piece {
151    type Error = ();
152
153    #[inline]
154    fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
155        if slice.len() != Self::SIZE {
156            return Err(());
157        }
158
159        Ok(Self(CowBytes::Shared(Bytes::copy_from_slice(slice))))
160    }
161}
162
163impl TryFrom<Vec<u8>> for Piece {
164    type Error = ();
165
166    #[inline]
167    fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
168        if vec.len() != Self::SIZE {
169            return Err(());
170        }
171
172        Ok(Self(CowBytes::Shared(Bytes::from(vec))))
173    }
174}
175
176impl TryFrom<Bytes> for Piece {
177    type Error = ();
178
179    #[inline]
180    fn try_from(bytes: Bytes) -> Result<Self, Self::Error> {
181        if bytes.len() != Self::SIZE {
182            return Err(());
183        }
184
185        Ok(Self(CowBytes::Shared(bytes)))
186    }
187}
188
189impl TryFrom<BytesMut> for Piece {
190    type Error = ();
191
192    #[inline]
193    fn try_from(bytes: BytesMut) -> Result<Self, Self::Error> {
194        if bytes.len() != Self::SIZE {
195            return Err(());
196        }
197
198        Ok(Self(CowBytes::Owned(bytes)))
199    }
200}
201
202impl From<&PieceArray> for Piece {
203    #[inline]
204    fn from(value: &PieceArray) -> Self {
205        Self(CowBytes::Shared(Bytes::copy_from_slice(value.as_ref())))
206    }
207}
208
209impl Deref for Piece {
210    type Target = PieceArray;
211
212    #[inline]
213    fn deref(&self) -> &Self::Target {
214        <&[u8; Self::SIZE]>::try_from(self.as_ref())
215            .expect("Slice of memory has correct length; qed")
216            .into()
217    }
218}
219
220impl DerefMut for Piece {
221    #[inline]
222    fn deref_mut(&mut self) -> &mut Self::Target {
223        <&mut [u8; Self::SIZE]>::try_from(self.as_mut())
224            .expect("Slice of memory has correct length; qed")
225            .into()
226    }
227}
228
229impl AsRef<[u8]> for Piece {
230    #[inline]
231    fn as_ref(&self) -> &[u8] {
232        self.0.as_ref()
233    }
234}
235
236impl AsMut<[u8]> for Piece {
237    #[inline]
238    fn as_mut(&mut self) -> &mut [u8] {
239        self.0.as_mut()
240    }
241}
242
243impl Piece {
244    /// Size of a piece (in bytes).
245    pub const SIZE: usize = PieceArray::SIZE;
246
247    /// Ensure piece contains cheaply cloneable shared data.
248    ///
249    /// Internally piece uses CoW mechanism and can store either mutable owned data or data that is
250    /// cheap to clone, calling this method will ensure further clones will not result in additional
251    /// memory allocations.
252    pub fn to_shared(self) -> Self {
253        Self(match self.0 {
254            CowBytes::Shared(bytes) => CowBytes::Shared(bytes),
255            CowBytes::Owned(bytes) => CowBytes::Shared(bytes.freeze()),
256        })
257    }
258}