1use alloc::vec::Vec;
17use digest::Digest;
18use digest::typenum::U32;
19use smallvec::{Array, SmallVec};
20
21use crate::collections::MAX_VEC_LEN;
22use crate::merkle::{merkleize, mix_in_length, pack_bytes};
23use crate::vector::decode_var_collection;
24use crate::{BYTES_PER_LENGTH_OFFSET, Decode, DecodeError, Encode, HashTreeRoot};
25
26impl<A: Array> Encode for SmallVec<A>
27where
28 A::Item: Encode,
29{
30 fn is_ssz_fixed_len() -> bool {
31 false
32 }
33 fn ssz_fixed_len() -> usize {
34 BYTES_PER_LENGTH_OFFSET
35 }
36 fn ssz_bytes_len(&self) -> usize {
37 if A::Item::is_ssz_fixed_len() {
38 A::Item::ssz_fixed_len() * self.len()
39 } else {
40 let mut total = self.len() * BYTES_PER_LENGTH_OFFSET;
41 for item in self {
42 total += item.ssz_bytes_len();
43 }
44 total
45 }
46 }
47 fn ssz_append(&self, buf: &mut Vec<u8>) {
48 if A::Item::is_ssz_fixed_len() {
49 for item in self {
50 item.ssz_append(buf);
51 }
52 return;
53 }
54 let n = self.len();
56 let header = n * BYTES_PER_LENGTH_OFFSET;
57 let start = buf.len();
58 buf.resize(start + header, 0u8);
59 let mut running = header as u32;
60 for (i, item) in self.iter().enumerate() {
61 let off_pos = start + i * BYTES_PER_LENGTH_OFFSET;
62 buf[off_pos..off_pos + 4].copy_from_slice(&running.to_le_bytes());
63 let before = buf.len();
64 item.ssz_append(buf);
65 let after = buf.len();
66 running = running
67 .checked_add((after - before) as u32)
68 .expect("ssz offset overflow");
69 }
70 }
71}
72
73impl<A: Array> Decode for SmallVec<A>
74where
75 A::Item: Decode,
76{
77 fn is_ssz_fixed_len() -> bool {
78 false
79 }
80 fn ssz_fixed_len() -> usize {
81 BYTES_PER_LENGTH_OFFSET
82 }
83 fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
84 let items: Vec<A::Item> = if A::Item::is_ssz_fixed_len() {
85 let elem = A::Item::ssz_fixed_len();
86 if elem == 0 {
87 return Err(DecodeError::Custom(
88 "zero-sized fixed-length SmallVec element",
89 ));
90 }
91 if !bytes.len().is_multiple_of(elem) {
92 return Err(DecodeError::LengthMismatch {
93 expected: bytes.len().div_ceil(elem) * elem,
94 actual: bytes.len(),
95 });
96 }
97 let n = bytes.len() / elem;
98 if (n as u64) > MAX_VEC_LEN {
99 return Err(DecodeError::BoundExceeded {
100 len: n as u64,
101 bound: MAX_VEC_LEN,
102 });
103 }
104 let mut out = Vec::with_capacity(n);
105 for i in 0..n {
106 let s = i * elem;
107 out.push(A::Item::from_ssz_bytes(&bytes[s..s + elem])?);
108 }
109 out
110 } else {
111 let out: Vec<A::Item> = decode_var_collection::<A::Item>(bytes, None)?;
112 if (out.len() as u64) > MAX_VEC_LEN {
113 return Err(DecodeError::BoundExceeded {
114 len: out.len() as u64,
115 bound: MAX_VEC_LEN,
116 });
117 }
118 out
119 };
120 Ok(SmallVec::from_vec(items))
123 }
124}
125
126impl<A: Array> HashTreeRoot for SmallVec<A>
127where
128 A::Item: HashTreeRoot + Encode,
129{
130 fn hash_tree_root<D: Digest<OutputSize = U32>>(&self) -> [u8; 32] {
131 let len = self.len() as u64;
132 let inner_root = if A::Item::is_basic_type() {
133 let mut buf: Vec<u8> = Vec::new();
134 for t in self {
135 t.ssz_append(&mut buf);
136 }
137 let chunks = pack_bytes(&buf);
138 let cap_bytes = (MAX_VEC_LEN as usize).saturating_mul(A::Item::ssz_fixed_len());
139 let chunk_limit = cap_bytes.div_ceil(32).max(1);
140 merkleize::<D>(&chunks, chunk_limit)
141 } else {
142 let roots: Vec<[u8; 32]> = self.iter().map(|t| t.hash_tree_root::<D>()).collect();
143 merkleize::<D>(&roots, (MAX_VEC_LEN as usize).max(1))
144 };
145 mix_in_length::<D>(inner_root, len)
146 }
147}