use core::{ffi::CStr, fmt, ops::Deref};
use std::ffi::CString;
use sqlite::{SQLITE_OPEN_MEMORY, SQLITE_OPEN_URI};
use crate::ffi;
pub trait Endpoint: Clone + fmt::Debug {
fn location(&self) -> &CStr;
fn flags(&self) -> i32 {
0
}
fn vfs(&self) -> Option<&CStr> {
None
}
}
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
#[cfg(sqlite_has_memory_database)]
pub struct Memory;
#[cfg(sqlite_has_memory_database)]
impl Endpoint for Memory {
fn location(&self) -> &CStr {
c""
}
fn flags(&self) -> i32 {
SQLITE_OPEN_MEMORY
}
}
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
#[repr(transparent)]
pub struct Local<L: ffi::Location = CString> {
path: L,
}
impl<L: ffi::Location> Local<L> {
pub fn new(path: impl ffi::IntoLocation<Location = L>) -> Self {
Self {
path: path.into_location(),
}
}
}
impl Local<&'static CStr> {
pub const fn define(path: &'static CStr) -> Self {
Self { path }
}
}
impl<L: ffi::Location> Endpoint for Local<L> {
fn location(&self) -> &CStr {
self.path.as_ref()
}
}
impl<L: ffi::Location> AsRef<L> for Local<L> {
fn as_ref(&self) -> &L {
&self.path
}
}
impl<L: ffi::Location> Deref for Local<L> {
type Target = L;
fn deref(&self) -> &Self::Target {
&self.path
}
}
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
#[repr(transparent)]
pub struct Uri<L: ffi::Location = CString> {
uri: L,
}
impl<L: ffi::Location> Uri<L> {
pub fn new(uri: impl ffi::IntoLocation<Location = L>) -> Self {
Self {
uri: uri.into_location(),
}
}
}
impl Uri<&'static CStr> {
pub const fn define(uri: &'static CStr) -> Self {
Self { uri }
}
}
impl<L: ffi::Location> Endpoint for Uri<L> {
fn location(&self) -> &CStr {
self.uri.as_ref()
}
fn flags(&self) -> i32 {
SQLITE_OPEN_URI
}
}
impl<L: ffi::Location> AsRef<L> for Uri<L> {
fn as_ref(&self) -> &L {
&self.uri
}
}
impl<L: ffi::Location> Deref for Uri<L> {
type Target = L;
fn deref(&self) -> &Self::Target {
&self.uri
}
}
#[cfg(feature = "url")]
#[cfg_attr(docsrs, doc(cfg(feature = "url")))]
impl From<url::Url> for Uri {
fn from(value: url::Url) -> Self {
Self::new(value.as_str())
}
}
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub struct Vfs<E: Endpoint = Local, L: ffi::Location = CString> {
endpoint: E,
vfs: L,
}
impl<E: Endpoint, L: ffi::Location> Vfs<E, L> {
pub fn new(endpoint: impl Into<E>, vfs: impl ffi::IntoLocation<Location = L>) -> Self {
Self {
endpoint: endpoint.into(),
vfs: vfs.into_location(),
}
}
}
impl<E: Endpoint> Vfs<E, &'static CStr> {
pub const fn define(endpoint: E, vfs: &'static CStr) -> Self {
Self { endpoint, vfs }
}
}
impl<E: Endpoint, L: ffi::Location> Endpoint for Vfs<E, L> {
fn location(&self) -> &CStr {
self.endpoint.location()
}
fn flags(&self) -> i32 {
self.endpoint.flags()
}
fn vfs(&self) -> Option<&CStr> {
Some(self.vfs.as_ref())
}
}
impl<E: Endpoint, L: ffi::Location> AsRef<E> for Vfs<E, L> {
fn as_ref(&self) -> &E {
&self.endpoint
}
}
impl<E: Endpoint, L: ffi::Location> Deref for Vfs<E, L> {
type Target = E;
fn deref(&self) -> &Self::Target {
&self.endpoint
}
}
pub trait IntoEndpoint {
type Endpoint: Endpoint;
fn into_endpoint(self) -> Self::Endpoint;
}
#[cfg(sqlite_has_memory_database)]
impl IntoEndpoint for Memory {
type Endpoint = Self;
fn into_endpoint(self) -> Self::Endpoint {
self
}
}
impl<L: ffi::Location> IntoEndpoint for Local<L> {
type Endpoint = Self;
fn into_endpoint(self) -> Self::Endpoint {
self
}
}
impl<L: ffi::Location> IntoEndpoint for Uri<L> {
type Endpoint = Self;
fn into_endpoint(self) -> Self::Endpoint {
self
}
}
impl<E: Endpoint, L: ffi::Location> IntoEndpoint for Vfs<E, L> {
type Endpoint = Self;
fn into_endpoint(self) -> Self::Endpoint {
self
}
}
impl<L: ffi::IntoLocation> IntoEndpoint for L {
type Endpoint = Local<L::Location>;
fn into_endpoint(self) -> Self::Endpoint {
Local::new(self)
}
}