quantydb_sqlite/
source.rs1use std::fs::File;
15use std::path::Path;
16
17use crate::error::{Result, SqliteError};
18
19pub trait Source {
20 fn read_at(&self, offset: u64, buf: &mut [u8]) -> Result<()>;
23
24 fn len(&self) -> Result<u64>;
26
27 fn is_empty(&self) -> Result<bool> {
28 Ok(self.len()? == 0)
29 }
30
31 fn accounts_for_wal(&self) -> bool {
40 false
41 }
42}
43
44pub struct FileSource {
46 file: File,
47 no_log_beside_it: bool,
51}
52
53impl FileSource {
54 pub fn open(path: impl AsRef<Path>) -> Result<Self> {
55 let path = path.as_ref();
56 let file = File::open(path)?;
57 let mut log = path.as_os_str().to_os_string();
59 log.push("-wal");
60 let no_log_beside_it = match std::fs::metadata(Path::new(&log)) {
61 Ok(meta) => meta.len() == 0,
62 Err(_) => true,
63 };
64 Ok(FileSource {
65 file,
66 no_log_beside_it,
67 })
68 }
69}
70
71#[cfg(unix)]
72impl Source for FileSource {
73 fn accounts_for_wal(&self) -> bool {
74 self.no_log_beside_it
75 }
76
77 fn read_at(&self, offset: u64, buf: &mut [u8]) -> Result<()> {
78 use std::os::unix::fs::FileExt;
79 self.file.read_exact_at(buf, offset)?;
80 Ok(())
81 }
82
83 fn len(&self) -> Result<u64> {
84 Ok(self.file.metadata()?.len())
85 }
86}
87
88#[cfg(windows)]
89impl Source for FileSource {
90 fn accounts_for_wal(&self) -> bool {
91 self.no_log_beside_it
92 }
93
94 fn read_at(&self, offset: u64, buf: &mut [u8]) -> Result<()> {
95 use std::os::windows::fs::FileExt;
96 let mut done = 0;
97 while done < buf.len() {
98 let n = self
99 .file
100 .seek_read(&mut buf[done..], offset + done as u64)?;
101 if n == 0 {
102 return Err(SqliteError::Io(std::io::Error::from(
103 std::io::ErrorKind::UnexpectedEof,
104 )));
105 }
106 done += n;
107 }
108 Ok(())
109 }
110
111 fn len(&self) -> Result<u64> {
112 Ok(self.file.metadata()?.len())
113 }
114}
115
116pub struct SliceSource<'a> {
118 bytes: &'a [u8],
119}
120
121impl<'a> SliceSource<'a> {
122 pub fn new(bytes: &'a [u8]) -> Self {
123 SliceSource { bytes }
124 }
125}
126
127impl Source for SliceSource<'_> {
128 fn read_at(&self, offset: u64, buf: &mut [u8]) -> Result<()> {
129 let start = usize::try_from(offset).map_err(|_| {
130 SqliteError::Io(std::io::Error::from(std::io::ErrorKind::UnexpectedEof))
131 })?;
132 let end = start.checked_add(buf.len()).ok_or_else(|| {
133 SqliteError::Io(std::io::Error::from(std::io::ErrorKind::UnexpectedEof))
134 })?;
135 if end > self.bytes.len() {
136 return Err(SqliteError::Io(std::io::Error::from(
137 std::io::ErrorKind::UnexpectedEof,
138 )));
139 }
140 buf.copy_from_slice(&self.bytes[start..end]);
141 Ok(())
142 }
143
144 fn len(&self) -> Result<u64> {
145 Ok(self.bytes.len() as u64)
146 }
147}