use std::{
fmt,
sync::atomic::{AtomicU32, Ordering},
};
use crate::rsapi::TursoError;
pub mod capi;
pub mod rsapi;
#[macro_export]
macro_rules! assert_send {
($($ty:ty),+ $(,)?) => {
const _: fn() = || {
fn check<T: Send>() {}
$( check::<$ty>(); )+
};
};
}
#[macro_export]
macro_rules! assert_sync {
($($ty:ty),+ $(,)?) => {
const _: fn() = || {
fn check<T: Sync>() {}
$( check::<$ty>(); )+
};
};
}
#[derive(Clone, Default)]
pub enum IoBackend {
#[default]
Default,
Memory,
Syscall,
IoUring,
IOCP,
Other(String),
}
impl fmt::Display for IoBackend {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Memory => write!(f, "memory"),
Self::Syscall => write!(f, "syscall"),
Self::IoUring => write!(f, "io_uring"),
Self::IOCP => write!(f, "experimental_win_iocp"),
Self::Other(other) => write!(f, "{other}"),
Self::Default => write!(f, "default"),
}
}
}
impl<T: AsRef<str>> From<T> for IoBackend {
fn from(vfs: T) -> Self {
match vfs.as_ref() {
"memory" => IoBackend::Memory,
"syscall" => IoBackend::Syscall,
"io_uring" => IoBackend::IoUring,
"experimental_win_iocp" => IoBackend::IOCP,
vfs => IoBackend::Other(vfs.to_string()),
}
}
}
struct ConcurrentGuard {
in_use: AtomicU32,
}
struct ConcurrentGuardToken<'a> {
guard: &'a ConcurrentGuard,
}
impl ConcurrentGuard {
pub fn new() -> Self {
Self {
in_use: AtomicU32::new(0),
}
}
pub fn try_use(&self) -> Result<ConcurrentGuardToken<'_>, TursoError> {
if self
.in_use
.compare_exchange(0, 1, Ordering::SeqCst, Ordering::SeqCst)
.is_err()
{
return Err(TursoError::Misuse("concurrent use forbidden".to_string()));
};
Ok(ConcurrentGuardToken { guard: self })
}
}
impl<'a> Drop for ConcurrentGuardToken<'a> {
fn drop(&mut self) {
let before = self.guard.in_use.swap(0, Ordering::SeqCst);
assert!(
before == 1,
"invalid db state: guard wasn't in use while token is active"
);
}
}