use std::ffi::{c_int, CStr};
use std::marker::PhantomData;
use std::num::NonZeroU32;
use super::{BusyHandler, CheckpointCallback, Sqlite3File, Vfs, Wal, WalManager};
#[derive(Clone)]
pub struct WalWrapper<T, W> {
wrapper: T,
wrapped: W,
}
impl<T, W> WalWrapper<T, W>
where
T: WrapWal<W::Wal> + Clone,
W: WalManager,
{
pub fn new(wrapper: T, wrapped: W) -> Self {
Self { wrapper, wrapped }
}
pub fn wrapped(&self) -> &W {
&self.wrapped
}
pub fn wrapper(&self) -> &T {
&self.wrapper
}
}
pub struct WrappedWal<T, W> {
wrapper: T,
wrapped: W,
}
pub struct WalRef<T, W> {
wrapper: *mut T,
wrapped: *mut W,
}
impl<T: WrapWal<W>, W: Wal> Wal for WalRef<T, W> {
fn limit(&mut self, size: i64) {
unsafe { (&mut *self.wrapper).limit(&mut *self.wrapped, size) }
}
fn begin_read_txn(&mut self) -> super::Result<bool> {
unsafe { (&mut *self.wrapper).begin_read_txn(&mut *self.wrapped) }
}
fn end_read_txn(&mut self) {
unsafe { (&mut *self.wrapper).end_read_txn(&mut *self.wrapped) }
}
fn find_frame(&mut self, page_no: NonZeroU32) -> super::Result<Option<NonZeroU32>> {
unsafe { (&mut *self.wrapper).find_frame(&mut *self.wrapped, page_no) }
}
fn read_frame(&mut self, frame_no: NonZeroU32, buffer: &mut [u8]) -> super::Result<()> {
unsafe { (&mut *self.wrapper).read_frame(&mut *self.wrapped, frame_no, buffer) }
}
fn db_size(&self) -> u32 {
unsafe { (&*self.wrapper).db_size(&*self.wrapped) }
}
fn begin_write_txn(&mut self) -> super::Result<()> {
unsafe { (&mut *self.wrapper).begin_write_txn(&mut *self.wrapped) }
}
fn end_write_txn(&mut self) -> super::Result<()> {
unsafe { (&mut *self.wrapper).end_write_txn(&mut *self.wrapped) }
}
fn undo<U: super::UndoHandler>(&mut self, handler: Option<&mut U>) -> super::Result<()> {
unsafe { (&mut *self.wrapper).undo(&mut *self.wrapped, handler) }
}
fn savepoint(&mut self, rollback_data: &mut [u32]) {
unsafe { (&mut *self.wrapper).savepoint(&mut *self.wrapped, rollback_data) }
}
fn savepoint_undo(&mut self, rollback_data: &mut [u32]) -> super::Result<()> {
unsafe { (&mut *self.wrapper).savepoint_undo(&mut *self.wrapped, rollback_data) }
}
fn insert_frames(
&mut self,
page_size: c_int,
page_headers: &mut super::PageHeaders,
size_after: u32,
is_commit: bool,
sync_flags: c_int,
) -> super::Result<usize> {
unsafe {
(&mut *self.wrapper).insert_frames(
&mut *self.wrapped,
page_size,
page_headers,
size_after,
is_commit,
sync_flags,
)
}
}
fn checkpoint(
&mut self,
db: &mut super::Sqlite3Db,
mode: super::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>,
) -> super::Result<()> {
unsafe {
(&mut *self.wrapper).checkpoint(
&mut *self.wrapped,
db,
mode,
busy_handler,
sync_flags,
buf,
checkpoint_cb,
in_wal,
backfilled,
)
}
}
fn exclusive_mode(&mut self, op: c_int) -> super::Result<()> {
unsafe { (&mut *self.wrapper).exclusive_mode(&mut *self.wrapped, op) }
}
fn uses_heap_memory(&self) -> bool {
unsafe { (&*self.wrapper).uses_heap_memory(&*self.wrapped) }
}
fn set_db(&mut self, db: &mut super::Sqlite3Db) {
unsafe { (&mut *self.wrapper).set_db(&mut *self.wrapped, db) }
}
fn callback(&self) -> i32 {
unsafe { (&*self.wrapper).callback(&*self.wrapped) }
}
fn frames_in_wal(&self) -> u32 {
unsafe { (&*self.wrapper).frames_in_wal(&*self.wrapped) }
}
}
impl<T, U> WalManager for WalWrapper<T, U>
where
T: WrapWal<U::Wal> + Clone,
U: WalManager,
{
type Wal = WrappedWal<T, U::Wal>;
fn use_shared_memory(&self) -> bool {
self.wrapped.use_shared_memory()
}
fn open(
&self,
vfs: &mut super::Vfs,
file: &mut super::Sqlite3File,
no_shm_mode: std::ffi::c_int,
max_log_size: i64,
db_path: &std::ffi::CStr,
) -> super::Result<Self::Wal> {
let wrapped =
self.wrapper
.open(&self.wrapped, vfs, file, no_shm_mode, max_log_size, db_path)?;
Ok(Self::Wal {
wrapper: self.wrapper.clone(),
wrapped,
})
}
fn close(
&self,
wal: &mut Self::Wal,
db: &mut super::Sqlite3Db,
sync_flags: std::ffi::c_int,
scratch: Option<&mut [u8]>,
) -> super::Result<()> {
self.wrapper
.clone()
.close(&self.wrapped, &mut wal.wrapped, db, sync_flags, scratch)
}
fn destroy_log(&self, vfs: &mut super::Vfs, db_path: &std::ffi::CStr) -> super::Result<()> {
self.wrapped.destroy_log(vfs, db_path)
}
fn log_exists(&self, vfs: &mut super::Vfs, db_path: &std::ffi::CStr) -> super::Result<bool> {
self.wrapped.log_exists(vfs, db_path)
}
fn destroy(self)
where
Self: Sized,
{
self.wrapped.destroy()
}
}
impl<T, W> Wal for WrappedWal<T, W>
where
T: WrapWal<W>,
W: Wal,
{
fn limit(&mut self, size: i64) {
self.wrapper.limit(&mut self.wrapped, size)
}
fn begin_read_txn(&mut self) -> super::Result<bool> {
self.wrapper.begin_read_txn(&mut self.wrapped)
}
fn end_read_txn(&mut self) {
self.wrapper.end_read_txn(&mut self.wrapped)
}
fn find_frame(&mut self, page_no: NonZeroU32) -> super::Result<Option<NonZeroU32>> {
self.wrapper.find_frame(&mut self.wrapped, page_no)
}
fn read_frame(&mut self, frame_no: NonZeroU32, buffer: &mut [u8]) -> super::Result<()> {
self.wrapper.read_frame(&mut self.wrapped, frame_no, buffer)
}
fn db_size(&self) -> u32 {
self.wrapper.db_size(&self.wrapped)
}
fn begin_write_txn(&mut self) -> super::Result<()> {
self.wrapper.begin_write_txn(&mut self.wrapped)
}
fn end_write_txn(&mut self) -> super::Result<()> {
self.wrapper.end_write_txn(&mut self.wrapped)
}
fn undo<U: super::UndoHandler>(&mut self, handler: Option<&mut U>) -> super::Result<()> {
self.wrapper.undo(&mut self.wrapped, handler)
}
fn savepoint(&mut self, rollback_data: &mut [u32]) {
self.wrapper.savepoint(&mut self.wrapped, rollback_data)
}
fn savepoint_undo(&mut self, rollback_data: &mut [u32]) -> super::Result<()> {
self.wrapper
.savepoint_undo(&mut self.wrapped, rollback_data)
}
fn insert_frames(
&mut self,
page_size: std::ffi::c_int,
page_headers: &mut super::PageHeaders,
size_after: u32,
is_commit: bool,
sync_flags: std::ffi::c_int,
) -> super::Result<usize> {
self.wrapper.insert_frames(
&mut self.wrapped,
page_size,
page_headers,
size_after,
is_commit,
sync_flags,
)
}
fn checkpoint(
&mut self,
db: &mut super::Sqlite3Db,
mode: super::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>,
) -> super::Result<()> {
self.wrapper.checkpoint(
&mut self.wrapped,
db,
mode,
busy_handler,
sync_flags,
buf,
checkpoint_cb,
in_wal,
backfilled,
)
}
fn exclusive_mode(&mut self, op: std::ffi::c_int) -> super::Result<()> {
self.wrapper.exclusive_mode(&mut self.wrapped, op)
}
fn uses_heap_memory(&self) -> bool {
self.wrapper.uses_heap_memory(&self.wrapped)
}
fn set_db(&mut self, db: &mut super::Sqlite3Db) {
self.wrapper.set_db(&mut self.wrapped, db)
}
fn callback(&self) -> i32 {
self.wrapper.callback(&self.wrapped)
}
fn frames_in_wal(&self) -> u32 {
self.wrapper.frames_in_wal(&self.wrapped)
}
}
pub trait WrapWal<W: Wal> {
fn limit(&mut self, wrapped: &mut W, size: i64) {
wrapped.limit(size)
}
fn begin_read_txn(&mut self, wrapped: &mut W) -> super::Result<bool> {
wrapped.begin_read_txn()
}
fn end_read_txn(&mut self, wrapped: &mut W) {
wrapped.end_read_txn()
}
fn find_frame(
&mut self,
wrapped: &mut W,
page_no: NonZeroU32,
) -> super::Result<Option<NonZeroU32>> {
wrapped.find_frame(page_no)
}
fn read_frame(
&mut self,
wrapped: &mut W,
frame_no: NonZeroU32,
buffer: &mut [u8],
) -> super::Result<()> {
wrapped.read_frame(frame_no, buffer)
}
fn db_size(&self, wrapped: &W) -> u32 {
wrapped.db_size()
}
fn begin_write_txn(&mut self, wrapped: &mut W) -> super::Result<()> {
wrapped.begin_write_txn()
}
fn end_write_txn(&mut self, wrapped: &mut W) -> super::Result<()> {
wrapped.end_write_txn()
}
fn undo<U: super::UndoHandler>(
&mut self,
wrapped: &mut W,
handler: Option<&mut U>,
) -> super::Result<()> {
wrapped.undo(handler)
}
fn savepoint(&mut self, wrapped: &mut W, rollback_data: &mut [u32]) {
wrapped.savepoint(rollback_data)
}
fn savepoint_undo(&mut self, wrapped: &mut W, rollback_data: &mut [u32]) -> super::Result<()> {
wrapped.savepoint_undo(rollback_data)
}
fn insert_frames(
&mut self,
wrapped: &mut W,
page_size: std::ffi::c_int,
page_headers: &mut super::PageHeaders,
size_after: u32,
is_commit: bool,
sync_flags: std::ffi::c_int,
) -> super::Result<usize> {
wrapped.insert_frames(page_size, page_headers, size_after, is_commit, sync_flags)
}
fn checkpoint(
&mut self,
wrapped: &mut W,
db: &mut super::Sqlite3Db,
mode: super::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>,
) -> super::Result<()> {
wrapped.checkpoint(
db,
mode,
busy_handler,
sync_flags,
buf,
checkpoint_cb,
in_wal,
backfilled,
)
}
fn exclusive_mode(&mut self, wrapped: &mut W, op: std::ffi::c_int) -> super::Result<()> {
wrapped.exclusive_mode(op)
}
fn uses_heap_memory(&self, wrapped: &W) -> bool {
wrapped.uses_heap_memory()
}
fn set_db(&mut self, wrapped: &mut W, db: &mut super::Sqlite3Db) {
wrapped.set_db(db)
}
fn callback(&self, wrapped: &W) -> i32 {
wrapped.callback()
}
fn frames_in_wal(&self, wrapped: &W) -> u32 {
wrapped.frames_in_wal()
}
fn open<M: WalManager<Wal = W>>(
&self,
manager: &M,
vfs: &mut Vfs,
file: &mut Sqlite3File,
no_shm_mode: c_int,
max_log_size: i64,
db_path: &CStr,
) -> super::Result<W> {
manager.open(vfs, file, no_shm_mode, max_log_size, db_path)
}
fn close<M: WalManager<Wal = W>>(
&mut self,
manager: &M,
wrapped: &mut W,
db: &mut super::Sqlite3Db,
sync_flags: c_int,
scratch: Option<&mut [u8]>,
) -> super::Result<()> {
manager.close(wrapped, db, sync_flags, scratch)
}
fn then<T>(self, other: T) -> Then<Self, T, W>
where
Self: Sized,
{
Then(self, other, PhantomData)
}
}
unsafe impl<A: Send, B: Send, W> Send for Then<A, B, W> {}
unsafe impl<A: Sync, B: Sync, W> Sync for Then<A, B, W> {}
pub struct Then<A, B, W>(A, B, PhantomData<W>);
impl<A: Clone, B: Clone, W> Clone for Then<A, B, W> {
fn clone(&self) -> Self {
Self(self.0.clone(), self.1.clone(), PhantomData)
}
}
impl<A, B, W> Then<A, B, W> {
pub fn wrapped(&self) -> &B {
&self.1
}
pub fn wrapper(&self) -> &A {
&self.0
}
pub fn map_wal<T>(self) -> Then<A, B, T> {
Then(self.0, self.1, PhantomData)
}
}
#[derive(Debug, Clone, Copy)]
pub struct PassthroughWalWrapper;
impl<W: Wal> WrapWal<W> for PassthroughWalWrapper {}
impl<A, B, W> WrapWal<W> for Then<A, B, W>
where
A: WrapWal<WalRef<B, W>>,
B: WrapWal<W>,
W: Wal,
{
fn limit(&mut self, wrapped: &mut W, size: i64) {
let mut r = WalRef {
wrapper: &mut self.1,
wrapped,
};
self.0.limit(&mut r, size)
}
fn begin_read_txn(&mut self, wrapped: &mut W) -> super::Result<bool> {
let mut r = WalRef {
wrapper: &mut self.1,
wrapped,
};
self.0.begin_read_txn(&mut r)
}
fn end_read_txn(&mut self, wrapped: &mut W) {
let mut r = WalRef {
wrapper: &mut self.1,
wrapped,
};
self.0.end_read_txn(&mut r)
}
fn find_frame(
&mut self,
wrapped: &mut W,
page_no: NonZeroU32,
) -> super::Result<Option<NonZeroU32>> {
let mut r = WalRef {
wrapper: &mut self.1,
wrapped,
};
self.0.find_frame(&mut r, page_no)
}
fn read_frame(
&mut self,
wrapped: &mut W,
frame_no: NonZeroU32,
buffer: &mut [u8],
) -> super::Result<()> {
let mut r = WalRef {
wrapper: &mut self.1,
wrapped,
};
self.0.read_frame(&mut r, frame_no, buffer)
}
fn db_size(&self, wrapped: &W) -> u32 {
let r = WalRef {
wrapper: &self.1 as *const B as *mut B,
wrapped: wrapped as *const W as *mut W,
};
self.0.db_size(&r)
}
fn begin_write_txn(&mut self, wrapped: &mut W) -> super::Result<()> {
let mut r = WalRef {
wrapper: &mut self.1,
wrapped,
};
self.0.begin_write_txn(&mut r)
}
fn end_write_txn(&mut self, wrapped: &mut W) -> super::Result<()> {
let mut r = WalRef {
wrapper: &mut self.1,
wrapped,
};
self.0.end_write_txn(&mut r)
}
fn undo<U: super::UndoHandler>(
&mut self,
wrapped: &mut W,
handler: Option<&mut U>,
) -> super::Result<()> {
let mut r = WalRef {
wrapper: &mut self.1,
wrapped,
};
self.0.undo(&mut r, handler)
}
fn savepoint(&mut self, wrapped: &mut W, rollback_data: &mut [u32]) {
let mut r = WalRef {
wrapper: &mut self.1,
wrapped,
};
self.0.savepoint(&mut r, rollback_data)
}
fn savepoint_undo(&mut self, wrapped: &mut W, rollback_data: &mut [u32]) -> super::Result<()> {
let mut r = WalRef {
wrapper: &mut self.1,
wrapped,
};
self.0.savepoint_undo(&mut r, rollback_data)
}
fn insert_frames(
&mut self,
wrapped: &mut W,
page_size: std::ffi::c_int,
page_headers: &mut super::PageHeaders,
size_after: u32,
is_commit: bool,
sync_flags: std::ffi::c_int,
) -> super::Result<usize> {
let mut r = WalRef {
wrapper: &mut self.1,
wrapped,
};
self.0.insert_frames(
&mut r,
page_size,
page_headers,
size_after,
is_commit,
sync_flags,
)
}
fn checkpoint(
&mut self,
wrapped: &mut W,
db: &mut super::Sqlite3Db,
mode: super::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>,
) -> super::Result<()> {
let mut r = WalRef {
wrapper: &mut self.1,
wrapped,
};
self.0.checkpoint(
&mut r,
db,
mode,
busy_handler,
sync_flags,
buf,
checkpoint_cb,
in_wal,
backfilled,
)
}
fn exclusive_mode(&mut self, wrapped: &mut W, op: std::ffi::c_int) -> super::Result<()> {
let mut r = WalRef {
wrapper: &mut self.1,
wrapped,
};
self.0.exclusive_mode(&mut r, op)
}
fn uses_heap_memory(&self, wrapped: &W) -> bool {
let r = WalRef {
wrapper: &self.1 as *const B as *mut B,
wrapped: wrapped as *const W as *mut W,
};
self.0.uses_heap_memory(&r)
}
fn set_db(&mut self, wrapped: &mut W, db: &mut super::Sqlite3Db) {
let mut r = WalRef {
wrapper: &mut self.1,
wrapped,
};
self.0.set_db(&mut r, db)
}
fn callback(&self, wrapped: &W) -> i32 {
let r = WalRef {
wrapper: &self.1 as *const B as *mut B,
wrapped: wrapped as *const W as *mut W,
};
self.0.callback(&r)
}
fn frames_in_wal(&self, wrapped: &W) -> u32 {
let r = WalRef {
wrapper: &self.1 as *const B as *mut B,
wrapped: wrapped as *const W as *mut W,
};
self.0.frames_in_wal(&r)
}
fn open<M: WalManager<Wal = W>>(
&self,
manager: &M,
vfs: &mut Vfs,
file: &mut Sqlite3File,
no_shm_mode: c_int,
max_log_size: i64,
db_path: &CStr,
) -> super::Result<W> {
manager.open(vfs, file, no_shm_mode, max_log_size, db_path)
}
fn close<M: WalManager<Wal = W>>(
&mut self,
manager: &M,
wrapped: &mut W,
db: &mut super::Sqlite3Db,
sync_flags: c_int,
scratch: Option<&mut [u8]>,
) -> super::Result<()> {
manager.close(wrapped, db, sync_flags, scratch)
}
}
impl<T: WrapWal<W>, W: Wal> WrapWal<W> for Option<T> {
fn limit(&mut self, wrapped: &mut W, size: i64) {
match self {
Some(t) => t.limit(wrapped, size),
None => wrapped.limit(size),
}
}
fn begin_read_txn(&mut self, wrapped: &mut W) -> super::Result<bool> {
match self {
Some(t) => t.begin_read_txn(wrapped),
None => wrapped.begin_read_txn(),
}
}
fn end_read_txn(&mut self, wrapped: &mut W) {
match self {
Some(t) => t.end_read_txn(wrapped),
None => wrapped.end_read_txn(),
}
}
fn find_frame(
&mut self,
wrapped: &mut W,
page_no: NonZeroU32,
) -> super::Result<Option<NonZeroU32>> {
match self {
Some(t) => t.find_frame(wrapped, page_no),
None => wrapped.find_frame(page_no),
}
}
fn read_frame(
&mut self,
wrapped: &mut W,
frame_no: NonZeroU32,
buffer: &mut [u8],
) -> super::Result<()> {
match self {
Some(t) => t.read_frame(wrapped, frame_no, buffer),
None => wrapped.read_frame(frame_no, buffer),
}
}
fn db_size(&self, wrapped: &W) -> u32 {
match self {
Some(t) => t.db_size(wrapped),
None => wrapped.db_size(),
}
}
fn begin_write_txn(&mut self, wrapped: &mut W) -> super::Result<()> {
match self {
Some(t) => t.begin_write_txn(wrapped),
None => wrapped.begin_write_txn(),
}
}
fn end_write_txn(&mut self, wrapped: &mut W) -> super::Result<()> {
match self {
Some(t) => t.end_write_txn(wrapped),
None => wrapped.end_write_txn(),
}
}
fn undo<U: super::UndoHandler>(
&mut self,
wrapped: &mut W,
handler: Option<&mut U>,
) -> super::Result<()> {
match self {
Some(t) => t.undo(wrapped, handler),
None => wrapped.undo(handler),
}
}
fn savepoint(&mut self, wrapped: &mut W, rollback_data: &mut [u32]) {
match self {
Some(t) => t.savepoint(wrapped, rollback_data),
None => wrapped.savepoint(rollback_data),
}
}
fn savepoint_undo(&mut self, wrapped: &mut W, rollback_data: &mut [u32]) -> super::Result<()> {
match self {
Some(t) => t.savepoint_undo(wrapped, rollback_data),
None => wrapped.savepoint_undo(rollback_data),
}
}
fn insert_frames(
&mut self,
wrapped: &mut W,
page_size: std::ffi::c_int,
page_headers: &mut super::PageHeaders,
size_after: u32,
is_commit: bool,
sync_flags: std::ffi::c_int,
) -> super::Result<usize> {
match self {
Some(t) => t.insert_frames(
wrapped,
page_size,
page_headers,
size_after,
is_commit,
sync_flags,
),
None => {
wrapped.insert_frames(page_size, page_headers, size_after, is_commit, sync_flags)
}
}
}
fn checkpoint(
&mut self,
wrapped: &mut W,
db: &mut super::Sqlite3Db,
mode: super::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>,
) -> super::Result<()> {
match self {
Some(t) => t.checkpoint(
wrapped,
db,
mode,
busy_handler,
sync_flags,
buf,
checkpoint_cb,
in_wal,
backfilled,
),
None => wrapped.checkpoint(
db,
mode,
busy_handler,
sync_flags,
buf,
checkpoint_cb,
in_wal,
backfilled,
),
}
}
fn exclusive_mode(&mut self, wrapped: &mut W, op: std::ffi::c_int) -> super::Result<()> {
match self {
Some(t) => t.exclusive_mode(wrapped, op),
None => wrapped.exclusive_mode(op),
}
}
fn uses_heap_memory(&self, wrapped: &W) -> bool {
match self {
Some(t) => t.uses_heap_memory(wrapped),
None => wrapped.uses_heap_memory(),
}
}
fn set_db(&mut self, wrapped: &mut W, db: &mut super::Sqlite3Db) {
match self {
Some(t) => t.set_db(wrapped, db),
None => wrapped.set_db(db),
}
}
fn callback(&self, wrapped: &W) -> i32 {
match self {
Some(t) => t.callback(wrapped),
None => wrapped.callback(),
}
}
fn frames_in_wal(&self, wrapped: &W) -> u32 {
match self {
Some(t) => t.frames_in_wal(wrapped),
None => wrapped.frames_in_wal(),
}
}
fn close<M: WalManager<Wal = W>>(
&mut self,
manager: &M,
wrapped: &mut W,
db: &mut super::Sqlite3Db,
sync_flags: c_int,
scratch: Option<&mut [u8]>,
) -> super::Result<()> {
match self {
Some(t) => t.close(manager, wrapped, db, sync_flags, scratch),
None => manager.close(wrapped, db, sync_flags, scratch),
}
}
}