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