tycho_storage_traits/
stored_value.rs1use bytes::Buf;
2use smallvec::SmallVec;
3use tycho_types::cell::HashBytes;
4use tycho_types::models::{BlockId, BlockIdShort, ShardIdent};
5
6pub trait StoredValue {
8 const SIZE_HINT: usize;
10
11 type OnStackSlice: smallvec::Array<Item = u8>;
13
14 fn serialize<T: StoredValueBuffer>(&self, buffer: &mut T);
16
17 fn deserialize(reader: &mut &[u8]) -> Self
24 where
25 Self: Sized;
26
27 #[inline(always)]
31 fn from_slice(mut data: &[u8]) -> Self
32 where
33 Self: Sized,
34 {
35 Self::deserialize(&mut data)
36 }
37
38 fn to_vec(&self) -> SmallVec<Self::OnStackSlice> {
40 let mut result = SmallVec::with_capacity(Self::SIZE_HINT);
41 self.serialize(&mut result);
42 result
43 }
44}
45
46pub trait StoredValueBuffer {
48 fn write_raw_slice(&mut self, data: &[u8]);
49}
50
51impl StoredValueBuffer for Vec<u8> {
52 #[inline(always)]
53 fn write_raw_slice(&mut self, data: &[u8]) {
54 self.extend_from_slice(data);
55 }
56}
57
58impl<T> StoredValueBuffer for SmallVec<T>
59where
60 T: smallvec::Array<Item = u8>,
61{
62 #[inline(always)]
63 fn write_raw_slice(&mut self, data: &[u8]) {
64 self.extend_from_slice(data);
65 }
66}
67
68impl StoredValue for BlockId {
69 const SIZE_HINT: usize = ShardIdent::SIZE_HINT + 4 + 32 + 32;
75
76 type OnStackSlice = [u8; Self::SIZE_HINT];
77
78 fn serialize<T: StoredValueBuffer>(&self, buffer: &mut T) {
79 self.shard.serialize(buffer);
80 buffer.write_raw_slice(&self.seqno.to_be_bytes());
81 buffer.write_raw_slice(self.root_hash.as_slice());
82 buffer.write_raw_slice(self.file_hash.as_slice());
83 }
84
85 fn deserialize(reader: &mut &[u8]) -> Self
86 where
87 Self: Sized,
88 {
89 debug_assert!(reader.remaining() >= Self::SIZE_HINT);
90
91 let shard = ShardIdent::deserialize(reader);
92 let seqno = reader.get_u32();
93
94 let mut root_hash = HashBytes::default();
95 root_hash.0.copy_from_slice(&reader[..32]);
96 let mut file_hash = HashBytes::default();
97 file_hash.0.copy_from_slice(&reader[32..]);
98
99 Self {
100 shard,
101 seqno,
102 root_hash,
103 file_hash,
104 }
105 }
106}
107
108impl StoredValue for ShardIdent {
109 const SIZE_HINT: usize = 4 + 8;
112
113 type OnStackSlice = [u8; Self::SIZE_HINT];
114
115 #[inline(always)]
116 fn serialize<T: StoredValueBuffer>(&self, buffer: &mut T) {
117 buffer.write_raw_slice(&self.workchain().to_be_bytes());
118 buffer.write_raw_slice(&self.prefix().to_be_bytes());
119 }
120
121 fn deserialize(reader: &mut &[u8]) -> Self
122 where
123 Self: Sized,
124 {
125 debug_assert!(reader.remaining() >= ShardIdent::SIZE_HINT);
126
127 let workchain = reader.get_u32() as i32;
128 let prefix = reader.get_u64();
129 unsafe { Self::new_unchecked(workchain, prefix) }
130 }
131}
132
133impl StoredValue for BlockIdShort {
134 const SIZE_HINT: usize = ShardIdent::SIZE_HINT + 4;
137
138 type OnStackSlice = [u8; Self::SIZE_HINT];
139
140 #[inline(always)]
141 fn serialize<T: StoredValueBuffer>(&self, buffer: &mut T) {
142 self.shard.serialize(buffer);
143 buffer.write_raw_slice(&self.seqno.to_be_bytes());
144 }
145
146 fn deserialize(reader: &mut &[u8]) -> Self
147 where
148 Self: Sized,
149 {
150 debug_assert!(reader.remaining() >= BlockIdShort::SIZE_HINT);
151
152 let shard = ShardIdent::deserialize(reader);
153 let seqno = reader.get_u32();
154 Self { shard, seqno }
155 }
156}
157
158#[cfg(test)]
159mod tests {
160 use super::*;
161
162 #[test]
163 fn fully_on_stack() {
164 assert!(!BlockId::default().to_vec().spilled());
165 assert!(!BlockId::default().to_vec().spilled());
166 }
167}