1use crate::e2s::error::E2sError;
12use ssz_derive::{Decode, Encode};
13use std::io::{self, Read, Write};
14
15pub const VERSION: [u8; 2] = [0x65, 0x32];
17
18pub const EMPTY: [u8; 2] = [0x00, 0x00];
20
21pub const SLOT_INDEX: [u8; 2] = [0x69, 0x32];
23
24#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode)]
26pub struct Header {
27 pub header_type: [u8; 2],
29
30 pub length: u32,
32
33 pub reserved: u16,
35}
36
37impl Header {
38 pub const SIZE: usize = 8;
40
41 pub const fn new(header_type: [u8; 2], length: u32) -> Self {
43 Self { header_type, length, reserved: 0 }
44 }
45
46 pub fn read<R: Read>(reader: &mut R) -> Result<Option<Self>, E2sError> {
48 let mut header_bytes = [0u8; 8];
49 match reader.read_exact(&mut header_bytes) {
50 Ok(_) => {}
51 Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => return Ok(None),
52 Err(e) => return Err(e.into()),
53 }
54
55 let header: Self = match ssz::Decode::from_ssz_bytes(&header_bytes) {
56 Ok(h) => h,
57 Err(_) => return Err(E2sError::Ssz(String::from("Failed to decode SSZ header"))),
58 };
59
60 if header.reserved != 0 {
61 return Err(E2sError::ReservedNotZero);
62 }
63
64 Ok(Some(header))
65 }
66
67 pub fn write<W: Write>(&self, writer: &mut W) -> io::Result<()> {
69 let encoded = ssz::Encode::as_ssz_bytes(self);
70 writer.write_all(&encoded)
71 }
72}
73
74#[derive(Debug, Clone, PartialEq, Eq, Default)]
76pub struct Version;
77
78impl Version {
79 pub fn encode<W: Write>(&self, writer: &mut W) -> io::Result<()> {
81 let header = Header::new(VERSION, 0);
82 header.write(writer)
83 }
84}
85
86#[derive(Debug, Clone)]
88pub struct Entry {
89 pub entry_type: [u8; 2],
91
92 pub data: Vec<u8>,
94}
95
96impl Entry {
97 pub const fn new(entry_type: [u8; 2], data: Vec<u8>) -> Self {
99 Self { entry_type, data }
100 }
101
102 pub const fn size(&self) -> usize {
104 Header::SIZE + self.data.len()
105 }
106
107 pub fn read<R: Read>(reader: &mut R) -> Result<Option<Self>, E2sError> {
109 let header = match Header::read(reader)? {
111 Some(h) => h,
112 None => return Ok(None),
113 };
114
115 let mut data = vec![0u8; header.length as usize];
117 match reader.read_exact(&mut data) {
118 Ok(_) => {}
119 Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => {
120 return Err(E2sError::Io(io::Error::new(
121 io::ErrorKind::UnexpectedEof,
122 "Unexpected EOF while reading entry data",
123 )));
124 }
125 Err(e) => return Err(e.into()),
126 }
127
128 Ok(Some(Self { entry_type: header.header_type, data }))
129 }
130
131 pub fn write<W: Write>(&self, writer: &mut W) -> io::Result<()> {
133 let header = Header::new(self.entry_type, self.data.len() as u32);
134 header.write(writer)?;
135 writer.write_all(&self.data)
136 }
137
138 pub fn is_version(&self) -> bool {
140 self.entry_type == VERSION
141 }
142
143 pub fn is_slot_index(&self) -> bool {
145 self.entry_type == SLOT_INDEX
146 }
147
148 pub fn ensure_type(&self, expected: [u8; 2], name: &str) -> Result<(), E2sError> {
152 if self.entry_type != expected {
153 return Err(E2sError::Ssz(format!(
154 "Invalid entry type for {name}: expected {:02x}{:02x}, got {:02x}{:02x}",
155 expected[0], expected[1], self.entry_type[0], self.entry_type[1]
156 )));
157 }
158 Ok(())
159 }
160}
161
162pub trait IndexEntry: Sized {
165 fn entry_type() -> [u8; 2];
167
168 fn new(starting_number: u64, offsets: Vec<i64>) -> Self;
170
171 fn starting_number(&self) -> u64;
173
174 fn offsets(&self) -> &[i64];
176
177 fn to_entry(&self) -> Entry {
180 let mut data = Vec::with_capacity(8 + self.offsets().len() * 8 + 8);
181
182 data.extend_from_slice(&self.starting_number().to_le_bytes());
184
185 data.extend(self.offsets().iter().flat_map(|offset| offset.to_le_bytes()));
187
188 let count = self.offsets().len() as i64;
190 data.extend_from_slice(&count.to_le_bytes());
191
192 Entry::new(Self::entry_type(), data)
193 }
194
195 fn from_entry(entry: &Entry) -> Result<Self, E2sError> {
197 entry.ensure_type(Self::entry_type(), "index")?;
198
199 if entry.data.len() < 16 {
200 return Err(E2sError::Ssz(
201 "Index entry too short: need at least 16 bytes for starting_number and count"
202 .to_string(),
203 ));
204 }
205
206 let count_bytes = &entry.data[entry.data.len() - 8..];
208 let count = i64::from_le_bytes(
209 count_bytes
210 .try_into()
211 .map_err(|_| E2sError::Ssz("Failed to read count bytes".to_string()))?,
212 ) as usize;
213
214 let expected_len = 8 + count * 8 + 8;
216 if entry.data.len() != expected_len {
217 return Err(E2sError::Ssz(format!(
218 "Index entry has incorrect length: expected {expected_len}, got {}",
219 entry.data.len()
220 )));
221 }
222
223 let starting_number = u64::from_le_bytes(
225 entry.data[0..8]
226 .try_into()
227 .map_err(|_| E2sError::Ssz("Failed to read starting_number bytes".to_string()))?,
228 );
229
230 let mut offsets = Vec::with_capacity(count);
232 for i in 0..count {
233 let start = 8 + i * 8;
234 let end = start + 8;
235 let offset_bytes = &entry.data[start..end];
236 let offset = i64::from_le_bytes(
237 offset_bytes
238 .try_into()
239 .map_err(|_| E2sError::Ssz(format!("Failed to read offset {i} bytes")))?,
240 );
241 offsets.push(offset);
242 }
243
244 Ok(Self::new(starting_number, offsets))
245 }
246}