1use crate::error::SQLiteError;
2
3pub struct Database<'a> {
4 pub header: DbHeader,
5 pub pages: Vec<Page<'a>>,
6}
7
8pub struct DbHeader {
9 pub page_size: PageSize,
10 pub write_version: u8,
11 pub read_version: u8,
12 pub max_payload_fraction: u8,
13 pub min_payload_fraction: u8,
14 pub leaf_payload_fraction: u8,
15 pub file_change_counter: u32,
16 pub db_size: u32,
17 pub first_freelist_page_no: u32,
18 pub total_freelist_pages: u32,
19 pub schema_cookie: u32,
20 pub schema_format_no: u32,
21 pub default_page_cache_size: u32,
22 pub no_largest_root_b_tree: u32,
23 pub db_text_encoding: TextEncoding,
24 pub user_version: u32,
25 pub incremental_vacuum_mode: u32,
26 pub application_id: u32,
27 pub version_valid_for_no: u32,
28 pub sqlite_version_number: u32,
29}
30
31pub struct PageSize(pub u16);
32
33impl PageSize {
34 pub fn real_size(&self) -> usize {
35 match self.0 {
36 1 => 0x1_00_00,
37 _ => self.0.into(),
38 }
39 }
40}
41
42#[derive(Copy, Clone)]
43pub enum TextEncoding {
44 Utf8,
45 Utf16Le,
46 Utf16Be,
47}
48
49impl TryFrom<u32> for TextEncoding {
50 type Error = SQLiteError;
51
52 fn try_from(value: u32) -> Result<Self, Self::Error> {
53 use TextEncoding::*;
54
55 match value {
56 1 => Ok(Utf8),
57 2 => Ok(Utf16Le),
58 3 => Ok(Utf16Be),
59 _ => Err(SQLiteError::UnknownTextEncodingError(value)),
60 }
61 }
62}
63
64pub enum Page<'a> {
65 InteriorIndex(InteriorIndexPage<'a>),
66 LeafIndex(LeafIndexPage<'a>),
67 InteriorTable(InteriorTablePage),
68 LeafTable(LeafTablePage<'a>),
69}
70
71pub struct InteriorPageHeader {
72 pub first_freeblock_offset: Option<u16>,
73 pub no_cells: u16,
74 pub cell_content_offset: CellOffset,
75 pub no_fragmented_bytes: u8,
76 pub rightmost_pointer: u32,
77}
78
79pub struct InteriorIndexPage<'a> {
80 pub header: InteriorPageHeader,
81 pub cell_pointers: Vec<u16>,
82 pub cells: Vec<InteriorIndexCell<'a>>,
83}
84
85pub struct InteriorTablePage {
86 pub header: InteriorPageHeader,
87 pub cell_pointers: Vec<u16>,
88 pub cells: Vec<InteriorTableCell>,
89}
90
91pub struct IndexCellPayload<'a> {
92 pub header_size: u64,
93 pub column_types: Vec<SerialType>,
94 pub column_values: Vec<Option<Payload<'a>>>,
95 pub rowid: u64,
96}
97
98pub struct InteriorIndexCell<'a> {
99 pub left_child_page_no: u32,
100 pub payload_size: u64,
101 pub payload: IndexCellPayload<'a>,
102 pub overflow_page_no: Option<u32>,
103}
104
105pub struct InteriorTableCell {
106 pub left_child_page_no: u32,
107 pub integer_key: u64,
108}
109
110pub struct CellOffset(pub u16);
111
112impl CellOffset {
113 pub fn real_offset(&self) -> u32 {
114 match self.0 {
115 0 => 0x1_00_00,
116 _ => self.0.into(),
117 }
118 }
119}
120
121pub struct LeafPageHeader {
122 pub first_freeblock_offset: Option<u16>,
123 pub no_cells: u16,
124 pub cell_content_offset: CellOffset,
125 pub no_fragmented_bytes: u8,
126}
127
128pub struct LeafIndexPage<'a> {
129 pub header: LeafPageHeader,
130 pub cell_pointers: Vec<u16>,
131 pub cells: Vec<LeafIndexCell<'a>>,
132}
133
134pub struct LeafIndexCell<'a> {
135 pub payload_size: u64,
136 pub payload: IndexCellPayload<'a>,
137 pub overflow_page_no: Option<u32>,
138}
139
140pub struct LeafTablePage<'a> {
141 pub header: LeafPageHeader,
142 pub cell_pointers: Vec<u16>,
143 pub cells: Vec<LeafTableCell<'a>>,
144}
145
146pub struct TableCellPayload<'a> {
147 pub header_size: u64,
148 pub column_types: Vec<SerialType>,
149 pub column_values: Vec<Option<Payload<'a>>>,
150}
151
152pub struct LeafTableCell<'a> {
153 pub payload_size: u64,
154 pub rowid: u64,
155 pub payload: TableCellPayload<'a>,
156 pub overflow_page_no: Option<u32>,
157}
158
159#[derive(Debug, Eq, PartialEq)]
160pub enum SerialType {
161 Null,
162 I8,
163 I16,
164 I24,
165 I32,
166 I48,
167 I64,
168 F64,
169 Const0,
170 Const1,
171 Reserved,
172 Blob(u64),
173 Text(u64),
174}
175
176impl From<u64> for SerialType {
177 fn from(value: u64) -> Self {
178 use SerialType::*;
179 match value {
180 0 => Null,
181 1 => I8,
182 2 => I16,
183 3 => I24,
184 4 => I32,
185 5 => I48,
186 6 => I64,
187 7 => F64,
188 8 => Const0,
189 9 => Const1,
190 10 | 11 => Reserved,
191 n if n >= 12 && n % 2 == 0 => Blob(n),
192 n if n >= 13 && n % 2 == 1 => Text(n),
193 _ => unreachable!(),
194 }
195 }
196}
197
198impl SerialType {
199 pub fn size(&self) -> usize {
200 match self {
201 SerialType::Null => 0,
202 SerialType::I8 => 1,
203 SerialType::I16 => 2,
204 SerialType::I24 => 3,
205 SerialType::I32 => 4,
206 SerialType::I48 => 6,
207 SerialType::I64 => 8,
208 SerialType::F64 => 8,
209 SerialType::Const0 => 0,
210 SerialType::Const1 => 0,
211 SerialType::Reserved => unimplemented!("reserved"),
212 SerialType::Blob(n) => ((n - 12) / 2).try_into().unwrap(),
213 SerialType::Text(n) => ((n - 13) / 2).try_into().unwrap(),
214 }
215 }
216}
217
218#[derive(Debug, Clone, PartialEq)]
219pub struct RawText<'a>(&'a [u8]);
220
221impl<'a> RawText<'a> {
222 pub fn new(v: &'a [u8]) -> Self {
223 RawText(v)
224 }
225
226 pub fn decode(&self, text_encoding: TextEncoding) -> String {
227 match text_encoding {
228 TextEncoding::Utf8 => String::from_utf8_lossy(self.0).to_string(),
229 TextEncoding::Utf16Le => unimplemented!("utf16 not supported yet"),
230 TextEncoding::Utf16Be => unimplemented!("utf16 not supported yet"),
231 }
232 }
233}
234
235impl<'a> From<&'a str> for RawText<'a> {
236 fn from(value: &'a str) -> Self {
237 RawText(value.as_bytes())
238 }
239}
240
241#[derive(Debug, Clone, PartialEq)]
242pub enum Payload<'a> {
243 I8(i8),
244 I16(i16),
245 I32(i32),
246 I64(i64),
247 F64(f64),
248 Blob(&'a [u8]),
249 Text(RawText<'a>),
250}
251
252impl<'a> From<&'a str> for Payload<'a> {
253 fn from(value: &'a str) -> Self {
254 Payload::Text(value.into())
255 }
256}
257
258impl<'a> From<&'a [u8]> for Payload<'a> {
259 fn from(value: &'a [u8]) -> Self {
260 Payload::Blob(value)
261 }
262}
263
264impl<'a> From<i8> for Payload<'a> {
265 fn from(value: i8) -> Self {
266 Payload::I8(value)
267 }
268}
269
270impl<'a> From<i16> for Payload<'a> {
271 fn from(value: i16) -> Self {
272 Payload::I16(value)
273 }
274}
275
276impl<'a> From<i32> for Payload<'a> {
277 fn from(value: i32) -> Self {
278 Payload::I32(value)
279 }
280}
281
282impl<'a> From<i64> for Payload<'a> {
283 fn from(value: i64) -> Self {
284 Payload::I64(value)
285 }
286}
287
288impl<'a> From<f64> for Payload<'a> {
289 fn from(value: f64) -> Self {
290 Payload::F64(value)
291 }
292}
293
294#[cfg(test)]
295impl<'a> Eq for Payload<'a> {}