ab_core_primitives/pieces/
piece.rs

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