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 fn new(header_type: [u8; 2], length: u32) -> Self {
40 Self { header_type, length, reserved: 0 }
41 }
42
43 pub fn read<R: Read>(reader: &mut R) -> Result<Option<Self>, E2sError> {
45 let mut header_bytes = [0u8; 8];
46 match reader.read_exact(&mut header_bytes) {
47 Ok(_) => {}
48 Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => return Ok(None),
49 Err(e) => return Err(e.into()),
50 }
51
52 let header: Self = match ssz::Decode::from_ssz_bytes(&header_bytes) {
53 Ok(h) => h,
54 Err(_) => return Err(E2sError::Ssz(String::from("Failed to decode SSZ header"))),
55 };
56
57 if header.reserved != 0 {
58 return Err(E2sError::ReservedNotZero);
59 }
60
61 Ok(Some(header))
62 }
63
64 pub fn write<W: Write>(&self, writer: &mut W) -> io::Result<()> {
66 let encoded = ssz::Encode::as_ssz_bytes(self);
67 writer.write_all(&encoded)
68 }
69}
70
71#[derive(Debug, Clone, PartialEq, Eq, Default)]
73pub struct Version;
74
75impl Version {
76 pub fn encode<W: Write>(&self, writer: &mut W) -> io::Result<()> {
78 let header = Header::new(VERSION, 0);
79 header.write(writer)
80 }
81}
82
83#[derive(Debug, Clone)]
85pub struct Entry {
86 pub entry_type: [u8; 2],
88
89 pub data: Vec<u8>,
91}
92
93impl Entry {
94 pub const fn new(entry_type: [u8; 2], data: Vec<u8>) -> Self {
96 Self { entry_type, data }
97 }
98
99 pub fn read<R: Read>(reader: &mut R) -> Result<Option<Self>, E2sError> {
101 let header = match Header::read(reader)? {
103 Some(h) => h,
104 None => return Ok(None),
105 };
106
107 let mut data = vec![0u8; header.length as usize];
109 match reader.read_exact(&mut data) {
110 Ok(_) => {}
111 Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => {
112 return Err(E2sError::Io(io::Error::new(
113 io::ErrorKind::UnexpectedEof,
114 "Unexpected EOF while reading entry data",
115 )));
116 }
117 Err(e) => return Err(e.into()),
118 }
119
120 Ok(Some(Self { entry_type: header.header_type, data }))
121 }
122
123 pub fn write<W: Write>(&self, writer: &mut W) -> io::Result<()> {
125 let header = Header::new(self.entry_type, self.data.len() as u32);
126 header.write(writer)?;
127 writer.write_all(&self.data)
128 }
129
130 pub fn is_version(&self) -> bool {
132 self.entry_type == VERSION
133 }
134
135 pub fn is_slot_index(&self) -> bool {
137 self.entry_type == SLOT_INDEX
138 }
139}
140
141pub trait IndexEntry: Sized {
144 fn entry_type() -> [u8; 2];
146
147 fn new(starting_number: u64, offsets: Vec<i64>) -> Self;
149
150 fn starting_number(&self) -> u64;
152
153 fn offsets(&self) -> &[i64];
155
156 fn to_entry(&self) -> Entry {
159 let mut data = Vec::with_capacity(8 + self.offsets().len() * 8 + 8);
160
161 data.extend_from_slice(&self.starting_number().to_le_bytes());
163
164 data.extend(self.offsets().iter().flat_map(|offset| offset.to_le_bytes()));
166
167 let count = self.offsets().len() as i64;
169 data.extend_from_slice(&count.to_le_bytes());
170
171 Entry::new(Self::entry_type(), data)
172 }
173
174 fn from_entry(entry: &Entry) -> Result<Self, E2sError> {
176 let expected_type = Self::entry_type();
177
178 if entry.entry_type != expected_type {
179 return Err(E2sError::Ssz(format!(
180 "Invalid entry type: expected {:02x}{:02x}, got {:02x}{:02x}",
181 expected_type[0], expected_type[1], entry.entry_type[0], entry.entry_type[1]
182 )));
183 }
184
185 if entry.data.len() < 16 {
186 return Err(E2sError::Ssz(
187 "Index entry too short: need at least 16 bytes for starting_number and count"
188 .to_string(),
189 ));
190 }
191
192 let count_bytes = &entry.data[entry.data.len() - 8..];
194 let count = i64::from_le_bytes(
195 count_bytes
196 .try_into()
197 .map_err(|_| E2sError::Ssz("Failed to read count bytes".to_string()))?,
198 ) as usize;
199
200 let expected_len = 8 + count * 8 + 8;
202 if entry.data.len() != expected_len {
203 return Err(E2sError::Ssz(format!(
204 "Index entry has incorrect length: expected {expected_len}, got {}",
205 entry.data.len()
206 )));
207 }
208
209 let starting_number = u64::from_le_bytes(
211 entry.data[0..8]
212 .try_into()
213 .map_err(|_| E2sError::Ssz("Failed to read starting_number bytes".to_string()))?,
214 );
215
216 let mut offsets = Vec::with_capacity(count);
218 for i in 0..count {
219 let start = 8 + i * 8;
220 let end = start + 8;
221 let offset_bytes = &entry.data[start..end];
222 let offset = i64::from_le_bytes(
223 offset_bytes
224 .try_into()
225 .map_err(|_| E2sError::Ssz(format!("Failed to read offset {i} bytes")))?,
226 );
227 offsets.push(offset);
228 }
229
230 Ok(Self::new(starting_number, offsets))
231 }
232}