Skip to main content

ab_core_primitives/
pieces.rs

1//! Pieces-related data structures.
2
3#[cfg(feature = "alloc")]
4mod cow_bytes;
5#[cfg(feature = "alloc")]
6mod flat_pieces;
7#[cfg(feature = "alloc")]
8mod piece;
9#[cfg(all(test, feature = "alloc"))]
10mod tests;
11
12#[cfg(feature = "alloc")]
13pub use crate::pieces::flat_pieces::FlatPieces;
14#[cfg(feature = "alloc")]
15pub use crate::pieces::piece::Piece;
16use crate::sectors::SBucket;
17use crate::segments::{
18    LocalSegmentIndex, RecordedHistorySegment, SegmentIndex, SegmentPosition, SegmentRoot,
19    SuperSegmentIndex, SuperSegmentRoot,
20};
21use crate::shard::ShardIndex;
22#[cfg(feature = "serde")]
23use ::serde::{Deserialize, Deserializer, Serialize, Serializer};
24use ab_io_type::trivial_type::{AnyBitPattern, TrivialType};
25use ab_io_type::unaligned::Unaligned;
26use ab_merkle_tree::blake3::BalancedMerkleTree;
27#[cfg(feature = "alloc")]
28use alloc::boxed::Box;
29#[cfg(feature = "alloc")]
30use alloc::vec::Vec;
31use array_reshape::{Flatten, Unflatten};
32use blake3::OUT_LEN;
33use core::array::TryFromSliceError;
34use core::hash::Hash;
35use core::iter::Step;
36use core::ops::{Index, IndexMut};
37use core::{fmt, mem};
38use derive_more::{
39    Add, AddAssign, AsMut, AsRef, Deref, DerefMut, Display, Div, DivAssign, From, Into, Mul,
40    MulAssign, Sub, SubAssign,
41};
42#[cfg(feature = "scale-codec")]
43use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
44#[cfg(feature = "serde")]
45use serde_big_array::BigArray;
46use transparent_wrapper::TransparentWrapper;
47
48/// Piece index
49#[derive(
50    Debug,
51    Display,
52    Default,
53    Copy,
54    Clone,
55    Ord,
56    PartialOrd,
57    Eq,
58    PartialEq,
59    Hash,
60    Add,
61    AddAssign,
62    Sub,
63    SubAssign,
64    Mul,
65    MulAssign,
66    Div,
67    DivAssign,
68)]
69#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
70#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
71#[repr(C)]
72pub struct PieceIndex(u64);
73
74impl Step for PieceIndex {
75    #[inline]
76    fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
77        u64::steps_between(&start.0, &end.0)
78    }
79
80    #[inline]
81    fn forward_checked(start: Self, count: usize) -> Option<Self> {
82        u64::forward_checked(start.0, count).map(Self)
83    }
84
85    #[inline(always)]
86    fn forward_overflowing(start: Self, count: usize) -> (Self, bool) {
87        let (n, overflowing) = u64::forward_overflowing(start.0, count);
88        (Self(n), overflowing)
89    }
90
91    #[inline]
92    fn backward_checked(start: Self, count: usize) -> Option<Self> {
93        u64::backward_checked(start.0, count).map(Self)
94    }
95
96    #[inline(always)]
97    fn backward_overflowing(start: Self, count: usize) -> (Self, bool) {
98        let (n, overflowing) = u64::backward_overflowing(start.0, count);
99        (Self(n), overflowing)
100    }
101}
102
103const impl From<u64> for PieceIndex {
104    #[inline(always)]
105    fn from(value: u64) -> Self {
106        Self(value)
107    }
108}
109
110const impl From<PieceIndex> for u64 {
111    #[inline(always)]
112    fn from(value: PieceIndex) -> Self {
113        value.0
114    }
115}
116
117impl PieceIndex {
118    /// Size in bytes.
119    pub const SIZE: usize = size_of::<u64>();
120    /// Piece index 0.
121    pub const ZERO: PieceIndex = PieceIndex(0);
122    /// Piece index 1.
123    pub const ONE: PieceIndex = PieceIndex(1);
124
125    /// Create a piece index from bytes.
126    #[inline]
127    pub const fn from_bytes(bytes: [u8; Self::SIZE]) -> Self {
128        Self(u64::from_le_bytes(bytes))
129    }
130
131    /// Convert a piece index to bytes.
132    #[inline]
133    pub const fn to_bytes(self) -> [u8; Self::SIZE] {
134        self.0.to_le_bytes()
135    }
136
137    /// Segment index piece index corresponds to
138    #[inline]
139    pub const fn segment_index(&self) -> SegmentIndex {
140        SegmentIndex::from(self.0 / RecordedHistorySegment::NUM_PIECES as u64)
141    }
142
143    /// Position of a piece in a segment
144    #[inline]
145    pub fn position(&self) -> PiecePosition {
146        PiecePosition::from((self.0 % RecordedHistorySegment::NUM_PIECES as u64) as u8)
147    }
148}
149
150const {
151    // Assert that `u8` represents `PiecePosition` perfectly
152    assert!(RecordedHistorySegment::NUM_PIECES == usize::from(u8::MAX) + 1);
153}
154
155/// Piece position in a segment
156#[derive(
157    Debug,
158    Display,
159    Default,
160    Copy,
161    Clone,
162    Ord,
163    PartialOrd,
164    Eq,
165    PartialEq,
166    Hash,
167    From,
168    Into,
169    TrivialType,
170)]
171#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
172#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
173#[repr(C)]
174pub struct PiecePosition(u8);
175
176impl Step for PiecePosition {
177    #[inline]
178    fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
179        u8::steps_between(&start.0, &end.0)
180    }
181
182    #[inline]
183    fn forward_checked(start: Self, count: usize) -> Option<Self> {
184        u8::forward_checked(start.0, count).map(Self)
185    }
186
187    #[inline(always)]
188    fn forward_overflowing(start: Self, count: usize) -> (Self, bool) {
189        let (n, overflowing) = u8::forward_overflowing(start.0, count);
190        (Self(n), overflowing)
191    }
192
193    #[inline]
194    fn backward_checked(start: Self, count: usize) -> Option<Self> {
195        u8::backward_checked(start.0, count).map(Self)
196    }
197
198    #[inline(always)]
199    fn backward_overflowing(start: Self, count: usize) -> (Self, bool) {
200        let (n, overflowing) = u8::backward_overflowing(start.0, count);
201        (Self(n), overflowing)
202    }
203}
204
205impl From<PiecePosition> for u16 {
206    #[inline]
207    fn from(original: PiecePosition) -> Self {
208        Self::from(original.0)
209    }
210}
211
212impl From<PiecePosition> for u32 {
213    #[inline]
214    fn from(original: PiecePosition) -> Self {
215        Self::from(original.0)
216    }
217}
218
219impl From<PiecePosition> for u64 {
220    #[inline]
221    fn from(original: PiecePosition) -> Self {
222        Self::from(original.0)
223    }
224}
225
226impl From<PiecePosition> for usize {
227    #[inline]
228    fn from(original: PiecePosition) -> Self {
229        usize::from(original.0)
230    }
231}
232
233/// Piece offset in a sector
234#[derive(
235    Debug,
236    Display,
237    Default,
238    Copy,
239    Clone,
240    Ord,
241    PartialOrd,
242    Eq,
243    PartialEq,
244    Hash,
245    From,
246    Into,
247    Add,
248    AddAssign,
249    Sub,
250    SubAssign,
251    Mul,
252    MulAssign,
253    Div,
254    DivAssign,
255    TrivialType,
256)]
257#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
258#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
259#[repr(C)]
260pub struct PieceOffset(u16);
261
262impl Step for PieceOffset {
263    #[inline]
264    fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
265        u16::steps_between(&start.0, &end.0)
266    }
267
268    #[inline]
269    fn forward_checked(start: Self, count: usize) -> Option<Self> {
270        u16::forward_checked(start.0, count).map(Self)
271    }
272
273    #[inline(always)]
274    fn forward_overflowing(start: Self, count: usize) -> (Self, bool) {
275        let (n, overflowing) = u16::forward_overflowing(start.0, count);
276        (Self(n), overflowing)
277    }
278
279    #[inline]
280    fn backward_checked(start: Self, count: usize) -> Option<Self> {
281        u16::backward_checked(start.0, count).map(Self)
282    }
283
284    #[inline(always)]
285    fn backward_overflowing(start: Self, count: usize) -> (Self, bool) {
286        let (n, overflowing) = u16::backward_overflowing(start.0, count);
287        (Self(n), overflowing)
288    }
289}
290
291impl From<PieceOffset> for u32 {
292    #[inline]
293    fn from(original: PieceOffset) -> Self {
294        Self::from(original.0)
295    }
296}
297
298impl From<PieceOffset> for u64 {
299    #[inline]
300    fn from(original: PieceOffset) -> Self {
301        Self::from(original.0)
302    }
303}
304
305impl From<PieceOffset> for usize {
306    #[inline]
307    fn from(original: PieceOffset) -> Self {
308        usize::from(original.0)
309    }
310}
311
312impl PieceOffset {
313    /// Piece index 0
314    pub const ZERO: Self = Self(0);
315    /// Piece index 1
316    pub const ONE: Self = Self(1);
317    /// Size in bytes
318    pub const SIZE: usize = size_of::<u16>();
319
320    /// Convert piece offset to bytes
321    #[inline]
322    pub const fn to_bytes(self) -> [u8; Self::SIZE] {
323        self.0.to_le_bytes()
324    }
325}
326
327/// Chunk contained in a record
328#[derive(
329    Default,
330    Copy,
331    Clone,
332    Eq,
333    PartialEq,
334    Ord,
335    PartialOrd,
336    Hash,
337    From,
338    Into,
339    AsRef,
340    AsMut,
341    Deref,
342    DerefMut,
343    TrivialType,
344    TransparentWrapper,
345)]
346#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
347#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
348#[cfg_attr(feature = "serde", serde(transparent))]
349#[repr(C)]
350pub struct RecordChunk([u8; RecordChunk::SIZE]);
351
352impl fmt::Debug for RecordChunk {
353    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
354        for byte in self.0 {
355            write!(f, "{byte:02x}")?;
356        }
357        Ok(())
358    }
359}
360
361impl RecordChunk {
362    /// Size of the chunk in bytes
363    pub const SIZE: usize = 32;
364
365    /// Convenient conversion from slice to underlying representation for efficiency purposes
366    #[inline]
367    pub fn slice_to_repr(value: &[Self]) -> &[[u8; Self::SIZE]] {
368        Self::peel_slice(value)
369    }
370
371    /// Convenient conversion from slice of underlying representation for efficiency purposes
372    #[inline]
373    pub fn slice_from_repr(value: &[[u8; Self::SIZE]]) -> &[Self] {
374        Self::wrap_slice(value)
375    }
376
377    /// Convenient conversion from mutable slice to underlying representation for efficiency
378    /// purposes
379    #[inline]
380    pub fn slice_mut_to_repr(value: &mut [Self]) -> &mut [[u8; Self::SIZE]] {
381        Self::peel_slice_mut(value)
382    }
383
384    /// Convenient conversion from mutable slice of underlying representation for efficiency
385    /// purposes
386    #[inline]
387    pub fn slice_mut_from_repr(value: &mut [[u8; Self::SIZE]]) -> &mut [Self] {
388        Self::wrap_slice_mut(value)
389    }
390
391    /// Convenient conversion from an array to underlying representation for efficiency purposes
392    #[inline(always)]
393    pub const fn array_to_repr<const N: usize>(value: &[Self; N]) -> &[[u8; Self::SIZE]; N] {
394        // SAFETY: `RecordChunk` is `#[repr(C)]` with a single field, so it has the same memory
395        // layout as its inner value, and arrays of them have the same memory layout too
396        unsafe { mem::transmute(value) }
397    }
398
399    /// Convenient conversion from an array of underlying representation for efficiency purposes
400    #[inline(always)]
401    pub const fn array_from_repr<const N: usize>(value: &[[u8; Self::SIZE]; N]) -> &[Self; N] {
402        // SAFETY: `RecordChunk` is `#[repr(C)]` with a single field, so it has the same memory
403        // layout as its inner value, and arrays of them have the same memory layout too
404        unsafe { mem::transmute(value) }
405    }
406
407    /// Convenient conversion from a mutable array to underlying representation for efficiency
408    /// purposes
409    #[inline(always)]
410    pub const fn array_mut_to_repr<const N: usize>(
411        value: &mut [Self; N],
412    ) -> &mut [[u8; Self::SIZE]; N] {
413        // SAFETY: `RecordChunk` is `#[repr(C)]` with a single field, so it has the same memory
414        // layout as its inner value, and arrays of them have the same memory layout too
415        unsafe { mem::transmute(value) }
416    }
417
418    /// Convenient conversion from a mutable array of underlying representation for efficiency
419    /// purposes
420    #[inline(always)]
421    pub const fn array_mut_from_repr<const N: usize>(
422        value: &mut [[u8; Self::SIZE]; N],
423    ) -> &mut [Self; N] {
424        // SAFETY: `RecordChunk` is `#[repr(C)]` with a single field, so it has the same memory
425        // layout as its inner value, and arrays of them have the same memory layout too
426        unsafe { mem::transmute(value) }
427    }
428}
429
430/// Record contained within a piece.
431///
432/// NOTE: This is a stack-allocated data structure and can cause stack overflow!
433#[derive(Copy, Clone, Eq, PartialEq, Deref, DerefMut, TrivialType, TransparentWrapper)]
434#[repr(C)]
435pub struct Record([[u8; RecordChunk::SIZE]; Record::NUM_CHUNKS]);
436
437impl fmt::Debug for Record {
438    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
439        for byte in self.0.as_flattened() {
440            write!(f, "{byte:02x}")?;
441        }
442        Ok(())
443    }
444}
445
446impl AsRef<[u8]> for Record {
447    #[inline]
448    fn as_ref(&self) -> &[u8] {
449        self.0.as_flattened()
450    }
451}
452
453impl AsRef<[u8; Record::SIZE]> for Record {
454    #[inline(always)]
455    fn as_ref(&self) -> &[u8; Record::SIZE] {
456        self.as_bytes()
457    }
458}
459
460impl AsMut<[u8; Record::SIZE]> for Record {
461    #[inline(always)]
462    fn as_mut(&mut self) -> &mut [u8; Record::SIZE] {
463        self.as_bytes_mut()
464    }
465}
466
467impl AsMut<[u8]> for Record {
468    #[inline]
469    fn as_mut(&mut self) -> &mut [u8] {
470        self.0.as_flattened_mut()
471    }
472}
473
474impl<'a> From<&'a Record> for &'a [[u8; RecordChunk::SIZE]; Record::NUM_CHUNKS] {
475    #[inline]
476    fn from(value: &'a Record) -> Self {
477        value.peel_ref()
478    }
479}
480
481impl<'a> From<&'a [[u8; RecordChunk::SIZE]; Record::NUM_CHUNKS]> for &'a Record {
482    #[inline]
483    fn from(value: &'a [[u8; RecordChunk::SIZE]; Record::NUM_CHUNKS]) -> Self {
484        Record::wrap_ref(value)
485    }
486}
487
488impl<'a> From<&'a mut Record> for &'a mut [[u8; RecordChunk::SIZE]; Record::NUM_CHUNKS] {
489    #[inline]
490    fn from(value: &'a mut Record) -> Self {
491        value.peel_mut()
492    }
493}
494
495impl<'a> From<&'a mut [[u8; RecordChunk::SIZE]; Record::NUM_CHUNKS]> for &'a mut Record {
496    #[inline]
497    fn from(value: &'a mut [[u8; RecordChunk::SIZE]; Record::NUM_CHUNKS]) -> Self {
498        Record::wrap_mut(value)
499    }
500}
501
502impl Record {
503    /// Number of chunks within one record.
504    pub const NUM_CHUNKS: usize = 2usize.pow(15);
505    /// Number of s-buckets contained within one sector record.
506    ///
507    /// Essentially we chunk records and erasure code them.
508    pub const NUM_S_BUCKETS: usize = Record::NUM_CHUNKS
509        * RecordedHistorySegment::ERASURE_CODING_RATE.1
510        / RecordedHistorySegment::ERASURE_CODING_RATE.0;
511    /// Size of a segment record, it is guaranteed to be a multiple of [`RecordChunk::SIZE`]
512    pub const SIZE: usize = RecordChunk::SIZE * Record::NUM_CHUNKS;
513
514    /// Create boxed value without hitting stack overflow
515    #[inline]
516    #[cfg(feature = "alloc")]
517    pub fn new_boxed() -> Box<Self> {
518        // TODO: Should have been just `::new()`, but https://github.com/rust-lang/rust/issues/53827
519        // SAFETY: Data structure filled with zeroes is a valid invariant
520        unsafe { Box::new_zeroed().assume_init() }
521    }
522
523    /// Create vector filled with zeroed records without hitting stack overflow
524    #[inline]
525    #[cfg(feature = "alloc")]
526    pub fn new_zero_vec(length: usize) -> Vec<Self> {
527        // TODO: Should have been just `vec![Self::default(); length]`, but
528        //  https://github.com/rust-lang/rust/issues/53827
529        // SAFETY: Data structure filled with zeroes is a valid invariant
530        unsafe { Box::<[Self]>::new_zeroed_slice(length).assume_init() }.into_vec()
531    }
532
533    /// Convenient conversion from slice of record to underlying representation for efficiency
534    /// purposes.
535    #[inline(always)]
536    pub fn slice_to_repr(value: &[Self]) -> &[[[u8; RecordChunk::SIZE]; Record::NUM_CHUNKS]] {
537        Self::peel_slice(value)
538    }
539
540    /// Convenient conversion from slice of underlying representation to record for efficiency
541    /// purposes.
542    #[inline(always)]
543    pub fn slice_from_repr(value: &[[[u8; RecordChunk::SIZE]; Record::NUM_CHUNKS]]) -> &[Self] {
544        Self::wrap_slice(value)
545    }
546
547    /// Convenient conversion from mutable slice of record to underlying representation for
548    /// efficiency purposes.
549    #[inline(always)]
550    pub fn slice_mut_to_repr(
551        value: &mut [Self],
552    ) -> &mut [[[u8; RecordChunk::SIZE]; Record::NUM_CHUNKS]] {
553        Self::peel_slice_mut(value)
554    }
555
556    /// Convenient conversion from mutable slice of underlying representation to record for
557    /// efficiency purposes.
558    #[inline(always)]
559    pub fn slice_mut_from_repr(
560        value: &mut [[[u8; RecordChunk::SIZE]; Record::NUM_CHUNKS]],
561    ) -> &mut [Self] {
562        Self::wrap_slice_mut(value)
563    }
564
565    /// Convenient conversion from an array of records to underlying representation for efficiency
566    /// purposes.
567    #[inline(always)]
568    pub const fn array_to_repr<const N: usize>(
569        value: &[Self; N],
570    ) -> &[[[u8; RecordChunk::SIZE]; Record::NUM_CHUNKS]; N] {
571        // SAFETY: `Record` is `#[repr(C)]` with a single field, so it has the same memory layout as
572        // its inner value, and arrays of them have the same memory layout too
573        unsafe { mem::transmute(value) }
574    }
575
576    /// Convenient conversion from an array of underlying representation to records for efficiency
577    /// purposes.
578    #[inline(always)]
579    pub const fn array_from_repr<const N: usize>(
580        value: &[[[u8; RecordChunk::SIZE]; Record::NUM_CHUNKS]; N],
581    ) -> &[Self; N] {
582        // SAFETY: `Record` is `#[repr(C)]` with a single field, so it has the same memory layout as
583        // its inner value, and arrays of them have the same memory layout too
584        unsafe { mem::transmute(value) }
585    }
586
587    /// Convenient conversion from a mutable array of records to underlying representation for
588    /// efficiency purposes.
589    #[inline(always)]
590    pub const fn array_mut_to_repr<const N: usize>(
591        value: &mut [Self; N],
592    ) -> &mut [[[u8; RecordChunk::SIZE]; Record::NUM_CHUNKS]; N] {
593        // SAFETY: `Record` is `#[repr(C)]` with a single field, so it has the same memory layout as
594        // its inner value, and arrays of them have the same memory layout too
595        unsafe { mem::transmute(value) }
596    }
597
598    /// Convenient conversion from a mutable array of underlying representation to records for
599    /// efficiency purposes.
600    #[inline(always)]
601    pub const fn array_mut_from_repr<const N: usize>(
602        value: &mut [[[u8; RecordChunk::SIZE]; Record::NUM_CHUNKS]; N],
603    ) -> &mut [Self; N] {
604        // SAFETY: `Record` is `#[repr(C)]` with a single field, so it has the same memory layout as
605        // its inner value, and arrays of them have the same memory layout too
606        unsafe { mem::transmute(value) }
607    }
608
609    /// Derive source chunks root on-demand
610    #[inline(always)]
611    pub fn source_chunks_root(&self) -> RecordChunksRoot {
612        RecordChunksRoot(BalancedMerkleTree::compute_root_only(self))
613    }
614}
615
616/// Source record together with parity chunks produced from it by erasure coding, which together
617/// are all s-buckets of a record.
618///
619/// NOTE: This is a stack-allocated data structure and can cause stack overflow!
620#[derive(Debug, Copy, Clone, Eq, PartialEq)]
621#[repr(C)]
622pub struct ExtendedRecord {
623    /// Source chunks
624    pub source: Record,
625    /// Parity chunks
626    pub parity: Record,
627}
628
629const {
630    // Conversions to and from `[Record; 2]` rely on this
631    assert!(size_of::<ExtendedRecord>() == size_of::<[Record; 2]>());
632    assert!(align_of::<ExtendedRecord>() == align_of::<[Record; 2]>());
633    // The last s-bucket is the last chunk of an extended record, which indexing relies on
634    assert!(usize::from(u16::from(SBucket::MAX)) == Record::NUM_S_BUCKETS - 1);
635}
636
637impl Index<SBucket> for ExtendedRecord {
638    type Output = RecordChunk;
639
640    #[inline(always)]
641    fn index(&self, index: SBucket) -> &Self::Output {
642        self.as_s_buckets()
643            .get(usize::from(index))
644            .expect("S-bucket is at most `SBucket::MAX`, which is within range, checked above; qed")
645    }
646}
647
648impl IndexMut<SBucket> for ExtendedRecord {
649    #[inline(always)]
650    fn index_mut(&mut self, index: SBucket) -> &mut Self::Output {
651        self.as_s_buckets_mut()
652            .get_mut(usize::from(index))
653            .expect("S-bucket is at most `SBucket::MAX`, which is within range, checked above; qed")
654    }
655}
656
657impl ExtendedRecord {
658    /// Create boxed value without hitting stack overflow
659    #[inline]
660    #[cfg(feature = "alloc")]
661    pub fn new_boxed() -> Box<Self> {
662        // TODO: Should have been just `::new()`, but https://github.com/rust-lang/rust/issues/53827
663        // SAFETY: Data structure filled with zeroes is a valid invariant
664        unsafe { Box::new_zeroed().assume_init() }
665    }
666
667    /// Source and parity records as an array
668    #[inline(always)]
669    pub const fn as_records(&self) -> &[Record; 2] {
670        // SAFETY: `#[repr(C)]` struct with two fields of the same type, which has the same size and
671        // alignment as an array of two elements of that type (checked above), hence no padding
672        unsafe { mem::transmute(self) }
673    }
674
675    /// Source and parity records as a mutable array
676    #[inline(always)]
677    pub const fn as_records_mut(&mut self) -> &mut [Record; 2] {
678        // SAFETY: `#[repr(C)]` struct with two fields of the same type, which has the same size and
679        // alignment as an array of two elements of that type (checked above), hence no padding
680        unsafe { mem::transmute(self) }
681    }
682
683    /// Chunks of all s-buckets, source chunks followed by parity chunks
684    #[inline(always)]
685    pub fn as_s_buckets(&self) -> &[RecordChunk; Record::NUM_S_BUCKETS] {
686        RecordChunk::array_from_repr(Record::array_to_repr(self.as_records()).flatten_ref())
687    }
688
689    /// Mutable chunks of all s-buckets, source chunks followed by parity chunks
690    #[inline(always)]
691    pub fn as_s_buckets_mut(&mut self) -> &mut [RecordChunk; Record::NUM_S_BUCKETS] {
692        RecordChunk::array_mut_from_repr(
693            Record::array_mut_to_repr(self.as_records_mut()).flatten_mut(),
694        )
695    }
696}
697
698/// Root of the record contained within a piece.
699///
700/// This is a Merkle Tree root of the roots of source and parity record chunks.
701#[derive(
702    Copy, Clone, Eq, PartialEq, Hash, Deref, DerefMut, From, Into, TrivialType, TransparentWrapper,
703)]
704#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
705#[repr(C)]
706pub struct RecordRoot([u8; RecordRoot::SIZE]);
707
708impl fmt::Debug for RecordRoot {
709    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
710        for byte in self.0 {
711            write!(f, "{byte:02x}")?;
712        }
713        Ok(())
714    }
715}
716
717#[cfg(feature = "serde")]
718#[derive(Serialize, Deserialize)]
719#[serde(transparent)]
720struct RecordRootBinary(#[serde(with = "BigArray")] [u8; RecordRoot::SIZE]);
721
722#[cfg(feature = "serde")]
723#[derive(Serialize, Deserialize)]
724#[serde(transparent)]
725struct RecordRootHex(#[serde(with = "hex")] [u8; RecordRoot::SIZE]);
726
727#[cfg(feature = "serde")]
728impl Serialize for RecordRoot {
729    #[inline]
730    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
731    where
732        S: Serializer,
733    {
734        if serializer.is_human_readable() {
735            RecordRootHex(self.0).serialize(serializer)
736        } else {
737            RecordRootBinary(self.0).serialize(serializer)
738        }
739    }
740}
741
742#[cfg(feature = "serde")]
743impl<'de> Deserialize<'de> for RecordRoot {
744    #[inline]
745    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
746    where
747        D: Deserializer<'de>,
748    {
749        Ok(Self(if deserializer.is_human_readable() {
750            RecordRootHex::deserialize(deserializer)?.0
751        } else {
752            RecordRootBinary::deserialize(deserializer)?.0
753        }))
754    }
755}
756
757impl Default for RecordRoot {
758    #[inline]
759    fn default() -> Self {
760        Self([0; _])
761    }
762}
763
764impl TryFrom<&[u8]> for RecordRoot {
765    type Error = TryFromSliceError;
766
767    #[inline]
768    fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
769        <[u8; Self::SIZE]>::try_from(slice).map(Self)
770    }
771}
772
773impl AsRef<[u8]> for RecordRoot {
774    #[inline]
775    fn as_ref(&self) -> &[u8] {
776        &self.0
777    }
778}
779
780impl AsMut<[u8]> for RecordRoot {
781    #[inline]
782    fn as_mut(&mut self) -> &mut [u8] {
783        &mut self.0
784    }
785}
786
787impl<'a> From<&'a RecordRoot> for &'a [u8; RecordRoot::SIZE] {
788    #[inline]
789    fn from(value: &'a RecordRoot) -> Self {
790        value.peel_ref()
791    }
792}
793
794impl<'a> From<&'a [u8; RecordRoot::SIZE]> for &'a RecordRoot {
795    #[inline]
796    fn from(value: &'a [u8; RecordRoot::SIZE]) -> Self {
797        RecordRoot::wrap_ref(value)
798    }
799}
800
801impl<'a> From<&'a mut RecordRoot> for &'a mut [u8; RecordRoot::SIZE] {
802    #[inline]
803    fn from(value: &'a mut RecordRoot) -> Self {
804        value.peel_mut()
805    }
806}
807
808impl<'a> From<&'a mut [u8; RecordRoot::SIZE]> for &'a mut RecordRoot {
809    #[inline]
810    fn from(value: &'a mut [u8; RecordRoot::SIZE]) -> Self {
811        RecordRoot::wrap_mut(value)
812    }
813}
814
815impl RecordRoot {
816    /// Size of record root in bytes.
817    pub const SIZE: usize = 32;
818
819    /// Validate record root hash produced by the archiver
820    pub fn is_valid(
821        &self,
822        segment_root: &SegmentRoot,
823        record_proof: &RecordProof,
824        position: PiecePosition,
825    ) -> bool {
826        BalancedMerkleTree::<{ RecordedHistorySegment::NUM_PIECES }>::verify(
827            segment_root,
828            record_proof,
829            usize::from(position),
830            self.0,
831        )
832    }
833}
834
835/// Root of source or parity record chunks
836#[derive(
837    Copy, Clone, Eq, PartialEq, Hash, Deref, DerefMut, From, Into, TrivialType, TransparentWrapper,
838)]
839#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
840#[repr(C)]
841pub struct RecordChunksRoot([u8; RecordChunksRoot::SIZE]);
842
843impl fmt::Debug for RecordChunksRoot {
844    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
845        for byte in self.0 {
846            write!(f, "{byte:02x}")?;
847        }
848        Ok(())
849    }
850}
851
852#[cfg(feature = "serde")]
853#[derive(Serialize, Deserialize)]
854#[serde(transparent)]
855struct RecordChunksRootBinary(#[serde(with = "BigArray")] [u8; RecordChunksRoot::SIZE]);
856
857#[cfg(feature = "serde")]
858#[derive(Serialize, Deserialize)]
859#[serde(transparent)]
860struct RecordChunksRootHex(#[serde(with = "hex")] [u8; RecordChunksRoot::SIZE]);
861
862#[cfg(feature = "serde")]
863impl Serialize for RecordChunksRoot {
864    #[inline]
865    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
866    where
867        S: Serializer,
868    {
869        if serializer.is_human_readable() {
870            RecordChunksRootHex(self.0).serialize(serializer)
871        } else {
872            RecordChunksRootBinary(self.0).serialize(serializer)
873        }
874    }
875}
876
877#[cfg(feature = "serde")]
878impl<'de> Deserialize<'de> for RecordChunksRoot {
879    #[inline]
880    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
881    where
882        D: Deserializer<'de>,
883    {
884        Ok(Self(if deserializer.is_human_readable() {
885            RecordChunksRootHex::deserialize(deserializer)?.0
886        } else {
887            RecordChunksRootBinary::deserialize(deserializer)?.0
888        }))
889    }
890}
891
892impl Default for RecordChunksRoot {
893    #[inline]
894    fn default() -> Self {
895        Self([0; _])
896    }
897}
898
899impl TryFrom<&[u8]> for RecordChunksRoot {
900    type Error = TryFromSliceError;
901
902    #[inline]
903    fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
904        <[u8; Self::SIZE]>::try_from(slice).map(Self)
905    }
906}
907
908impl AsRef<[u8]> for RecordChunksRoot {
909    #[inline]
910    fn as_ref(&self) -> &[u8] {
911        &self.0
912    }
913}
914
915impl AsMut<[u8]> for RecordChunksRoot {
916    #[inline]
917    fn as_mut(&mut self) -> &mut [u8] {
918        &mut self.0
919    }
920}
921
922impl<'a> From<&'a RecordChunksRoot> for &'a [u8; RecordChunksRoot::SIZE] {
923    #[inline]
924    fn from(value: &'a RecordChunksRoot) -> Self {
925        value.peel_ref()
926    }
927}
928
929impl<'a> From<&'a [u8; RecordChunksRoot::SIZE]> for &'a RecordChunksRoot {
930    #[inline]
931    fn from(value: &'a [u8; RecordChunksRoot::SIZE]) -> Self {
932        RecordChunksRoot::wrap_ref(value)
933    }
934}
935
936impl<'a> From<&'a mut RecordChunksRoot> for &'a mut [u8; RecordChunksRoot::SIZE] {
937    #[inline]
938    fn from(value: &'a mut RecordChunksRoot) -> Self {
939        value.peel_mut()
940    }
941}
942
943impl<'a> From<&'a mut [u8; RecordChunksRoot::SIZE]> for &'a mut RecordChunksRoot {
944    #[inline]
945    fn from(value: &'a mut [u8; RecordChunksRoot::SIZE]) -> Self {
946        RecordChunksRoot::wrap_mut(value)
947    }
948}
949
950impl RecordChunksRoot {
951    /// Size of record chunks root in bytes.
952    pub const SIZE: usize = 32;
953}
954
955/// Proof that the record (root) belongs to a segment
956#[derive(
957    Copy, Clone, Eq, PartialEq, Hash, Deref, DerefMut, From, Into, TrivialType, TransparentWrapper,
958)]
959#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
960#[repr(C)]
961pub struct RecordProof([[u8; OUT_LEN]; RecordProof::NUM_HASHES]);
962
963impl fmt::Debug for RecordProof {
964    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
965        write!(f, "[")?;
966        for hash in self.0 {
967            for byte in hash {
968                write!(f, "{byte:02x}")?;
969            }
970            write!(f, ", ")?;
971        }
972        write!(f, "]")?;
973        Ok(())
974    }
975}
976
977#[cfg(feature = "serde")]
978#[derive(Serialize, Deserialize)]
979#[serde(transparent)]
980struct RecordProofBinary([[u8; OUT_LEN]; RecordProof::NUM_HASHES]);
981
982#[cfg(feature = "serde")]
983#[derive(Serialize, Deserialize, TransparentWrapper)]
984#[serde(transparent)]
985#[repr(transparent)]
986struct RecordProofHexHash(#[serde(with = "hex")] [u8; OUT_LEN]);
987
988#[cfg(feature = "serde")]
989#[derive(Serialize, Deserialize)]
990#[serde(transparent)]
991struct RecordProofHex([RecordProofHexHash; RecordProof::NUM_HASHES]);
992
993#[cfg(feature = "serde")]
994impl Serialize for RecordProof {
995    #[inline]
996    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
997    where
998        S: Serializer,
999    {
1000        if serializer.is_human_readable() {
1001            RecordProofHex(<[RecordProofHexHash; Self::NUM_HASHES]>::wrap(self.0))
1002                .serialize(serializer)
1003        } else {
1004            RecordProofBinary(self.0).serialize(serializer)
1005        }
1006    }
1007}
1008
1009#[cfg(feature = "serde")]
1010impl<'de> Deserialize<'de> for RecordProof {
1011    #[inline]
1012    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1013    where
1014        D: Deserializer<'de>,
1015    {
1016        Ok(Self(if deserializer.is_human_readable() {
1017            RecordProofHex::deserialize(deserializer)?.0.peel()
1018        } else {
1019            RecordProofBinary::deserialize(deserializer)?.0
1020        }))
1021    }
1022}
1023
1024impl Default for RecordProof {
1025    #[inline]
1026    fn default() -> Self {
1027        Self([[0; OUT_LEN]; _])
1028    }
1029}
1030
1031impl AsRef<[u8]> for RecordProof {
1032    #[inline]
1033    fn as_ref(&self) -> &[u8] {
1034        self.0.as_flattened()
1035    }
1036}
1037
1038impl AsMut<[u8]> for RecordProof {
1039    #[inline]
1040    fn as_mut(&mut self) -> &mut [u8] {
1041        self.0.as_flattened_mut()
1042    }
1043}
1044
1045impl<'a> From<&'a RecordProof> for &'a [u8; RecordProof::SIZE] {
1046    #[inline]
1047    fn from(value: &'a RecordProof) -> Self {
1048        value.peel_ref().flatten_ref()
1049    }
1050}
1051
1052impl<'a> From<&'a [u8; RecordProof::SIZE]> for &'a RecordProof {
1053    #[inline]
1054    fn from(value: &'a [u8; RecordProof::SIZE]) -> Self {
1055        RecordProof::wrap_ref(value.unflatten_ref())
1056    }
1057}
1058
1059impl<'a> From<&'a mut RecordProof> for &'a mut [u8; RecordProof::SIZE] {
1060    #[inline]
1061    fn from(value: &'a mut RecordProof) -> Self {
1062        value.peel_mut().flatten_mut()
1063    }
1064}
1065
1066impl<'a> From<&'a mut [u8; RecordProof::SIZE]> for &'a mut RecordProof {
1067    #[inline]
1068    fn from(value: &'a mut [u8; RecordProof::SIZE]) -> Self {
1069        RecordProof::wrap_mut(value.unflatten_mut())
1070    }
1071}
1072
1073impl RecordProof {
1074    /// Size of record proof in bytes
1075    pub const SIZE: usize = OUT_LEN * Self::NUM_HASHES;
1076    const NUM_HASHES: usize = RecordedHistorySegment::NUM_PIECES.ilog2() as usize;
1077}
1078
1079/// Proof that the segment belongs to a super segment
1080#[derive(
1081    Copy, Clone, Eq, PartialEq, Hash, Deref, DerefMut, From, Into, TrivialType, TransparentWrapper,
1082)]
1083#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
1084#[repr(C)]
1085pub struct SegmentProof([[u8; OUT_LEN]; SegmentProof::NUM_HASHES]);
1086
1087impl fmt::Debug for SegmentProof {
1088    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1089        write!(f, "[")?;
1090        for hash in self.0 {
1091            for byte in hash {
1092                write!(f, "{byte:02x}")?;
1093            }
1094            write!(f, ", ")?;
1095        }
1096        write!(f, "]")?;
1097        Ok(())
1098    }
1099}
1100
1101#[cfg(feature = "serde")]
1102#[derive(Serialize, Deserialize)]
1103#[serde(transparent)]
1104struct SegmentProofBinary([[u8; OUT_LEN]; SegmentProof::NUM_HASHES]);
1105
1106#[cfg(feature = "serde")]
1107#[derive(Serialize, Deserialize, TransparentWrapper)]
1108#[serde(transparent)]
1109#[repr(transparent)]
1110struct SegmentProofHexHash(#[serde(with = "hex")] [u8; OUT_LEN]);
1111
1112#[cfg(feature = "serde")]
1113#[derive(Serialize, Deserialize)]
1114#[serde(transparent)]
1115struct SegmentProofHex([SegmentProofHexHash; SegmentProof::NUM_HASHES]);
1116
1117#[cfg(feature = "serde")]
1118impl Serialize for SegmentProof {
1119    #[inline]
1120    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1121    where
1122        S: Serializer,
1123    {
1124        if serializer.is_human_readable() {
1125            SegmentProofHex(<[SegmentProofHexHash; Self::NUM_HASHES]>::wrap(self.0))
1126                .serialize(serializer)
1127        } else {
1128            SegmentProofBinary(self.0).serialize(serializer)
1129        }
1130    }
1131}
1132
1133#[cfg(feature = "serde")]
1134impl<'de> Deserialize<'de> for SegmentProof {
1135    #[inline]
1136    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1137    where
1138        D: Deserializer<'de>,
1139    {
1140        Ok(Self(if deserializer.is_human_readable() {
1141            SegmentProofHex::deserialize(deserializer)?.0.peel()
1142        } else {
1143            SegmentProofBinary::deserialize(deserializer)?.0
1144        }))
1145    }
1146}
1147
1148impl Default for SegmentProof {
1149    #[inline]
1150    fn default() -> Self {
1151        Self([[0; OUT_LEN]; _])
1152    }
1153}
1154
1155impl AsRef<[u8]> for SegmentProof {
1156    #[inline]
1157    fn as_ref(&self) -> &[u8] {
1158        self.0.as_flattened()
1159    }
1160}
1161
1162impl AsMut<[u8]> for SegmentProof {
1163    #[inline]
1164    fn as_mut(&mut self) -> &mut [u8] {
1165        self.0.as_flattened_mut()
1166    }
1167}
1168
1169impl<'a> From<&'a SegmentProof> for &'a [u8; SegmentProof::SIZE] {
1170    #[inline]
1171    fn from(value: &'a SegmentProof) -> Self {
1172        value.peel_ref().flatten_ref()
1173    }
1174}
1175
1176impl<'a> From<&'a [u8; SegmentProof::SIZE]> for &'a SegmentProof {
1177    #[inline]
1178    fn from(value: &'a [u8; SegmentProof::SIZE]) -> Self {
1179        SegmentProof::wrap_ref(value.unflatten_ref())
1180    }
1181}
1182
1183impl<'a> From<&'a mut SegmentProof> for &'a mut [u8; SegmentProof::SIZE] {
1184    #[inline]
1185    fn from(value: &'a mut SegmentProof) -> Self {
1186        value.peel_mut().flatten_mut()
1187    }
1188}
1189
1190impl<'a> From<&'a mut [u8; SegmentProof::SIZE]> for &'a mut SegmentProof {
1191    #[inline]
1192    fn from(value: &'a mut [u8; SegmentProof::SIZE]) -> Self {
1193        SegmentProof::wrap_mut(value.unflatten_mut())
1194    }
1195}
1196
1197impl SegmentProof {
1198    /// Size of segment proof in bytes
1199    pub const SIZE: usize = OUT_LEN * Self::NUM_HASHES;
1200    const NUM_HASHES: usize = SuperSegmentRoot::MAX_SEGMENTS.next_power_of_two().ilog2() as usize;
1201}
1202
1203/// Header for a piece of archival history.
1204///
1205/// Primarily contains information needed for piece verification.
1206#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, TrivialType)]
1207#[cfg_attr(feature = "scale-codec", derive(Encode, Decode))]
1208#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1209#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
1210#[repr(C)]
1211pub struct PieceHeader {
1212    /// Shard index
1213    pub shard_index: Unaligned<ShardIndex>,
1214    /// Local segment index
1215    pub local_segment_index: Unaligned<LocalSegmentIndex>,
1216    /// Super segment index
1217    pub super_segment_index: Unaligned<SuperSegmentIndex>,
1218    /// Position of the segment in the super segment
1219    pub segment_position: Unaligned<SegmentPosition>,
1220    /// Segment root
1221    pub segment_root: SegmentRoot,
1222    /// Segment proof
1223    pub segment_proof: SegmentProof,
1224    /// Root of parity record chunks.
1225    ///
1226    /// Technically redundant, but helps to avoid repeating erasure coding during verification.
1227    pub parity_chunks_root: RecordChunksRoot,
1228    /// Proof that the record (root) belongs to a segment
1229    pub record_proof: RecordProof,
1230}
1231
1232const {
1233    // Must have minimal alignment for various conversions to/from bytes
1234    assert!(align_of::<PieceHeader>() == 1);
1235}
1236
1237/// A piece of archival history.
1238///
1239/// This version is allocated on the stack, for a heap-allocated piece that can be moved around
1240/// efficiently, see `Piece`.
1241///
1242/// Internally, a piece contains a record, supplementary record chunk root, and a proof proving this
1243/// piece belongs to can be used to verify that a piece belongs to the actual archival history of
1244/// the blockchain.
1245#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
1246#[repr(C)]
1247pub struct InnerPiece {
1248    /// Piece header
1249    pub header: PieceHeader,
1250    /// Record contained within a piece
1251    pub record: Record,
1252}
1253
1254const {
1255    const fn assert_any_bit_pattern<T>()
1256    where
1257        T: AnyBitPattern,
1258    {
1259    }
1260
1261    // Must have minimal alignment for various conversions to/from bytes
1262    assert!(align_of::<InnerPiece>() == 1);
1263    // No padding, which `Piece::from_parts()` relies on
1264    assert!(size_of::<InnerPiece>() == size_of::<PieceHeader>() + size_of::<Record>());
1265    // Any bit pattern must be a valid value for various conversions from bytes
1266    assert_any_bit_pattern::<InnerPiece>();
1267}
1268
1269impl InnerPiece {
1270    /// Size of a piece (in bytes)
1271    pub const SIZE: usize = size_of::<Self>();
1272
1273    /// Create boxed value without hitting stack overflow
1274    #[inline]
1275    #[cfg(feature = "alloc")]
1276    pub fn new_boxed() -> Box<Self> {
1277        // TODO: Should have been just `::new()`, but https://github.com/rust-lang/rust/issues/53827
1278        // SAFETY: Data structure filled with zeroes is a valid invariant
1279        unsafe { Box::<Self>::new_zeroed().assume_init() }
1280    }
1281
1282    /// Check whether the piece is valid against the matching super segment root
1283    pub fn is_valid(
1284        &self,
1285        super_segment_root: &SuperSegmentRoot,
1286        num_segments: u32,
1287        position: PiecePosition,
1288    ) -> bool {
1289        if !self.header.segment_root.is_valid(
1290            self.header.shard_index.as_inner(),
1291            self.header.local_segment_index.as_inner(),
1292            self.header.segment_position.as_inner(),
1293            &self.header.segment_proof,
1294            num_segments,
1295            super_segment_root,
1296        ) {
1297            return false;
1298        }
1299        self.record_root().is_valid(
1300            &self.header.segment_root,
1301            &self.header.record_proof,
1302            position,
1303        )
1304    }
1305
1306    /// Root of the record contained within a piece.
1307    ///
1308    /// It is re-derived on every call of this function.
1309    #[inline]
1310    pub fn record_root(&self) -> RecordRoot {
1311        let record_merkle_tree_root = BalancedMerkleTree::compute_root_only(&[
1312            *self.record.source_chunks_root(),
1313            *self.header.parity_chunks_root,
1314        ]);
1315
1316        RecordRoot::from(record_merkle_tree_root)
1317    }
1318
1319    /// Convenient conversion from slice of pieces to underlying representation for efficiency
1320    /// purposes.
1321    #[inline]
1322    pub fn slice_to_repr(value: &[Self]) -> &[[u8; Self::SIZE]] {
1323        // SAFETY: `InnerPiece` has alignment of 1 and any bit pattern is a valid value (both
1324        // checked above), it is `TrivialType`, so it has no padding
1325        unsafe { mem::transmute(value) }
1326    }
1327
1328    /// Convenient conversion from slice of underlying representation to pieces for efficiency
1329    /// purposes.
1330    #[inline]
1331    pub fn slice_from_repr(value: &[[u8; Self::SIZE]]) -> &[Self] {
1332        // SAFETY: `InnerPiece` has alignment of 1 and any bit pattern is a valid value (both
1333        // checked above), it is `TrivialType`, so it has no padding
1334        unsafe { mem::transmute(value) }
1335    }
1336
1337    /// Convenient conversion from mutable slice of pieces to underlying representation for
1338    /// efficiency purposes.
1339    #[inline]
1340    pub fn slice_mut_to_repr(value: &mut [Self]) -> &mut [[u8; Self::SIZE]] {
1341        // SAFETY: `InnerPiece` has alignment of 1 and any bit pattern is a valid value (both
1342        // checked above), it is `TrivialType`, so it has no padding
1343        unsafe { mem::transmute(value) }
1344    }
1345
1346    /// Convenient conversion from mutable slice of underlying representation to pieces for
1347    /// efficiency purposes.
1348    #[inline]
1349    pub fn slice_mut_from_repr(value: &mut [[u8; Self::SIZE]]) -> &mut [Self] {
1350        // SAFETY: `InnerPiece` has alignment of 1 and any bit pattern is a valid value (both
1351        // checked above), it is `TrivialType`, so it has no padding
1352        unsafe { mem::transmute(value) }
1353    }
1354}