sq3_rs/file_header/
page_size.rs

1use sq3_derive::Name;
2use sq3_parser::TypeName;
3
4use crate::{
5    result::{SqliteError, SqliteResult},
6    traits::ParseBytes,
7};
8/// # Page Size (2 Bytes)
9///
10///  The two-byte value beginning at offset 16 determines the page size of the
11/// database. For Sqlite versions 3.7.0.1 (2010-08-04) and earlier, this value
12/// is interpreted as a big-endian integer and must be a power of two between
13/// 512 and 32768, inclusive. Beginning with Sqlite version 3.7.1 (2010-08-23),
14/// a page size of 65536 bytes is supported. The value 65536 will not fit in a
15/// two-byte integer, so to specify a 65536-byte page size, the value at offset
16/// 16 is 0x00 0x01. This value can be interpreted as a big-endian 1 and
17/// thought of as a magic number to represent the 65536 page size. Or one can
18/// view the two-byte field as a little endian number and say that it
19/// represents the page size divided by 256. These two interpretations of the
20/// page-size field are equivalent.
21#[derive(Debug, Default, Name, PartialEq, Eq, Clone)]
22pub enum PageSize {
23    L512,
24    L1024,
25    L2048,
26    /// Reference: https://www.sqlite.org/pragma.html#pragma_page_size
27    #[default]
28    L4096,
29    L8192,
30    L16384,
31    L32768,
32    L65536,
33}
34
35impl PageSize {
36    pub const MAX: Self = Self::L65536;
37
38    pub fn iter() -> PageSizeIterator {
39        PageSizeIterator {
40            current: Some(PageSize::L512),
41        }
42    }
43}
44
45impl From<&PageSize> for u32 {
46    fn from(value: &PageSize) -> Self {
47        match *value {
48            PageSize::L512 => 512,
49            PageSize::L1024 => 1024,
50            PageSize::L2048 => 2048,
51            PageSize::L4096 => 4096,
52            PageSize::L8192 => 8192,
53            PageSize::L16384 => 16384,
54            PageSize::L32768 => 32768,
55            PageSize::L65536 => 65536,
56        }
57    }
58}
59
60impl PartialEq<usize> for PageSize {
61    fn eq(&self, other: &usize) -> bool {
62        match self {
63            PageSize::L512 => *other == 512,
64            PageSize::L1024 => *other == 1024,
65            PageSize::L2048 => *other == 2048,
66            PageSize::L4096 => *other == 4096,
67            PageSize::L8192 => *other == 8192,
68            PageSize::L16384 => *other == 16384,
69            PageSize::L32768 => *other == 32768,
70            PageSize::L65536 => *other == 655536,
71        }
72    }
73}
74
75impl PartialEq<PageSize> for usize {
76    fn eq(&self, other: &PageSize) -> bool {
77        match other {
78            PageSize::L512 => *self == 512,
79            PageSize::L1024 => *self == 1024,
80            PageSize::L2048 => *self == 2048,
81            PageSize::L4096 => *self == 4096,
82            PageSize::L8192 => *self == 8192,
83            PageSize::L16384 => *self == 16384,
84            PageSize::L32768 => *self == 32768,
85            PageSize::L65536 => *self == 655536,
86        }
87    }
88}
89
90impl ParseBytes for PageSize {
91    const LENGTH_BYTES: usize = 2;
92
93    fn parsing_handler(bytes: &[u8]) -> SqliteResult<Self> {
94        let buf: [u8; Self::LENGTH_BYTES] = bytes.try_into()?;
95
96        let page_size = u16::from_be_bytes(buf);
97
98        match page_size {
99            0 | 2..=511 => Err(SqliteError::Custom(
100                "PageSize can't be less than 512".into(),
101            )),
102            512 => Ok(Self::L512),
103            1024 => Ok(Self::L1024),
104            2048 => Ok(Self::L2048),
105            4096 => Ok(Self::L4096),
106            8192 => Ok(Self::L8192),
107            16384 => Ok(Self::L16384),
108            32768 => Ok(Self::L32768),
109            1 => Ok(Self::L65536),
110            _ => Err(SqliteError::Custom("PageSize must be power of two".into())),
111        }
112    }
113}
114
115#[derive(Debug)]
116pub struct PageSizeIterator {
117    current: Option<PageSize>,
118}
119
120impl Iterator for PageSizeIterator {
121    type Item = PageSize;
122
123    fn next(&mut self) -> Option<Self::Item> {
124        let current = self.current.take()?;
125
126        let new_current = match current {
127            PageSize::L512 => Some(PageSize::L1024),
128            PageSize::L1024 => Some(PageSize::L2048),
129            PageSize::L2048 => Some(PageSize::L4096),
130            PageSize::L4096 => Some(PageSize::L8192),
131            PageSize::L8192 => Some(PageSize::L16384),
132            PageSize::L16384 => Some(PageSize::L32768),
133            PageSize::L32768 => Some(PageSize::L65536),
134            PageSize::L65536 => None,
135        };
136
137        let value = current;
138
139        self.current = new_current;
140
141        Some(value)
142    }
143}
144
145#[cfg(test)]
146mod tests {
147    use super::*;
148
149    #[test]
150    fn ok_on_convert_pagesize_into_iterator() {
151        let vec = PageSize::iter().map(|i| (&i).into()).collect::<Vec<u32>>();
152
153        let expected = vec![512, 1024, 2048, 4096, 8192, 16384, 32768, 65536];
154
155        assert_eq!(vec, expected);
156    }
157}