sqlite_rs/header/
db_filesize_in_pages.rs

1use crate::result::SqliteError;
2use crate::traits::ParseBytes;
3use crate::{impl_name, result::SqliteResult};
4use core::ops::Deref;
5use std::num::NonZeroU32;
6
7/// # In-header database size (4 Bytes)
8///
9///  The in-header database size is a 4-byte big-endian integer at offset 28
10/// into the header stores the size of the database file in pages. If this
11/// in-header datasize size is not valid (see the next paragraph), then the
12/// database size is computed by looking at the actual size of the database
13/// file. Older versions of Sqlite ignored the in-header database size and used
14/// the actual file size exclusively. Newer versions of Sqlite use the in-header
15/// database size if it is available but fall back to the actual file size if
16/// the in-header database size is not valid.
17///
18///  The in-header database size is only considered to be valid if it is
19/// non-zero and if the 4-byte change counter at offset 24 exactly matches the
20/// 4-byte version-valid-for number at offset 92. The in-header database size is
21/// always valid when the database is only modified using recent versions of
22/// Sqlite, versions 3.7.0 (2010-07-21) and later. If a legacy version of Sqlite
23/// writes to the database, it will not know to update the in-header database
24/// size and so the in-header database size could be incorrect. But legacy
25/// versions of Sqlite will also leave the version-valid-for number at offset 92
26/// unchanged so it will not match the change-counter. Hence, invalid in-header
27/// database sizes can be detected (and ignored) by observing when the
28/// change-counter does not match the version-valid-for number.
29#[derive(Debug)]
30pub struct DatabaseFileSizeInPages(u32);
31
32impl Default for DatabaseFileSizeInPages {
33  fn default() -> Self {
34    Self(1)
35  }
36}
37impl Deref for DatabaseFileSizeInPages {
38  type Target = u32;
39
40  fn deref(&self) -> &Self::Target {
41    &self.0
42  }
43}
44impl_name! {DatabaseFileSizeInPages}
45
46impl ParseBytes for DatabaseFileSizeInPages {
47  const LENGTH_BYTES: usize = 4;
48
49  fn parsing_handler(bytes: &[u8]) -> SqliteResult<Self> {
50    let buf: [u8; Self::LENGTH_BYTES] = bytes.try_into()?;
51
52    let database_size = NonZeroU32::new(u32::from_be_bytes(buf)).ok_or(
53      SqliteError::Custom("DatabaseFileSizeInPages can't be `0`".into()),
54    )?;
55
56    Ok(Self(database_size.get()))
57  }
58}