use std::ffi::{c_int, CStr};
use std::num::NonZeroU32;
pub use crate::ffi::Error;
use crate::ffi::*;
pub use sqlite3_wal::{Sqlite3Wal, Sqlite3WalManager};
pub mod either;
pub(crate) mod ffi;
mod sqlite3_wal;
pub mod wrapper;
pub type Result<T, E = Error> = std::result::Result<T, E>;
pub use ffi::make_wal_manager;
use self::wrapper::{WalWrapper, WrapWal};
pub trait WalManager {
type Wal: Wal;
fn use_shared_memory(&self) -> bool;
fn open(
&self,
vfs: &mut Vfs,
file: &mut Sqlite3File,
no_shm_mode: c_int,
max_log_size: i64,
db_path: &CStr,
) -> Result<Self::Wal>;
fn close(
&self,
wal: &mut Self::Wal,
db: &mut Sqlite3Db,
sync_flags: c_int,
scratch: Option<&mut [u8]>,
) -> Result<()>;
fn destroy_log(&self, vfs: &mut Vfs, db_path: &CStr) -> Result<()>;
fn log_exists(&self, vfs: &mut Vfs, db_path: &CStr) -> Result<bool>;
fn destroy(self)
where
Self: Sized;
fn wrap<U>(self, wrapper: U) -> WalWrapper<U, Self>
where
U: WrapWal<Self::Wal> + Clone,
Self: Sized,
{
WalWrapper::new(wrapper, self)
}
}
pub struct Sqlite3Db {
inner: *mut sqlite3,
}
impl Sqlite3Db {
pub fn as_ptr(&mut self) -> *mut sqlite3 {
self.inner
}
}
#[repr(transparent)]
pub struct Sqlite3File {
inner: *mut sqlite3_file,
}
impl Sqlite3File {
pub(crate) fn as_ptr(&mut self) -> *mut sqlite3_file {
self.inner
}
pub fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<()> {
unsafe {
assert!(!self.inner.is_null());
let inner = &mut *self.inner;
assert!(!inner.pMethods.is_null());
let io_methods = &*inner.pMethods;
let read = io_methods.xRead.unwrap();
let rc = read(
self.inner,
buf.as_mut_ptr() as *mut _,
buf.len() as _,
offset as _,
);
if rc == 0 {
Ok(())
} else {
Err(Error::new(rc))
}
}
}
}
pub struct Vfs {
vfs: *mut sqlite3_vfs,
}
impl Vfs {
pub(crate) fn as_ptr(&mut self) -> *mut sqlite3_vfs {
self.vfs
}
}
pub struct PageHeaders {
inner: *mut libsql_pghdr,
}
impl PageHeaders {
pub(crate) fn as_ptr(&self) -> *const libsql_pghdr {
self.inner
}
pub(crate) fn as_mut_ptr(&mut self) -> *mut libsql_pghdr {
self.inner
}
pub unsafe fn from_raw(inner: *mut libsql_pghdr) -> Self {
Self { inner }
}
pub fn iter(&self) -> PageHdrIter {
PageHdrIter::new(self.as_ptr(), 4096)
}
pub unsafe fn iter_mut(&mut self) -> PageHdrIterMut {
PageHdrIterMut::new(self.as_mut_ptr(), 4096)
}
}
pub trait BusyHandler {
fn handle_busy(&mut self) -> bool;
}
impl<F> BusyHandler for F
where
F: FnMut() -> bool,
{
fn handle_busy(&mut self) -> bool {
(self)()
}
}
pub trait UndoHandler {
fn handle_undo(&mut self, page_no: u32) -> Result<()>;
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
#[repr(i32)]
pub enum CheckpointMode {
Passive = SQLITE_CHECKPOINT_PASSIVE,
Full = SQLITE_CHECKPOINT_FULL,
Restart = SQLITE_CHECKPOINT_RESTART,
Truncate = SQLITE_CHECKPOINT_TRUNCATE,
}
pub trait CheckpointCallback {
fn frame(
&mut self,
max_safe_frame_no: u32,
frame: &[u8],
page_no: NonZeroU32,
frame_no: NonZeroU32,
) -> Result<()>;
fn finish(&mut self) -> Result<()>;
}
pub trait Wal {
fn limit(&mut self, size: i64);
fn begin_read_txn(&mut self) -> Result<bool>;
fn end_read_txn(&mut self);
fn find_frame(&mut self, page_no: NonZeroU32) -> Result<Option<NonZeroU32>>;
fn read_frame(&mut self, frame_no: NonZeroU32, buffer: &mut [u8]) -> Result<()>;
fn frame_page_no(&self, frame_no: NonZeroU32) -> Option<NonZeroU32>;
fn db_size(&self) -> u32;
fn begin_write_txn(&mut self) -> Result<()>;
fn end_write_txn(&mut self) -> Result<()>;
fn undo<U: UndoHandler>(&mut self, handler: Option<&mut U>) -> Result<()>;
fn savepoint(&mut self, rollback_data: &mut [u32]);
fn savepoint_undo(&mut self, rollback_data: &mut [u32]) -> Result<()>;
fn insert_frames(
&mut self,
page_size: c_int,
page_headers: &mut PageHeaders,
size_after: u32,
is_commit: bool,
sync_flags: c_int,
) -> Result<usize>;
fn checkpoint(
&mut self,
db: &mut Sqlite3Db,
mode: CheckpointMode,
busy_handler: Option<&mut dyn BusyHandler>,
sync_flags: u32,
buf: &mut [u8],
checkpoint_cb: Option<&mut dyn CheckpointCallback>,
in_wal: Option<&mut i32>,
backfilled: Option<&mut i32>,
) -> Result<()>;
fn exclusive_mode(&mut self, op: c_int) -> Result<()>;
fn uses_heap_memory(&self) -> bool;
fn set_db(&mut self, db: &mut Sqlite3Db);
fn callback(&self) -> i32;
fn frames_in_wal(&self) -> u32;
fn backfilled(&self) -> u32;
fn db_file(&self) -> &Sqlite3File;
}