use core::{ops::Deref, slice};
use sqlite::{SQLITE_STATIC, sqlite3_column_blob, sqlite3_column_bytes, sqlite3_column_text};
#[cfg(target_pointer_width = "64")]
use sqlite::{SQLITE_UTF8, sqlite3_bind_blob64, sqlite3_bind_text64, sqlite3_uint64};
#[cfg(target_pointer_width = "32")]
use sqlite::{sqlite3_bind_blob, sqlite3_bind_text};
use crate::{
error::Result,
ffi::{Bind, Fetch, Statement},
types::{BindIndex, ColumnIndex},
};
#[cfg(target_pointer_width = "64")]
const ENCODING_UTF8: u8 = SQLITE_UTF8 as u8;
#[derive(Copy, Clone, Debug)]
#[repr(transparent)]
#[doc(alias = "SQLITE_STATIC")]
pub struct Borrowed<'a, T: ?Sized>(&'a T);
impl<'a, T: ?Sized> Borrowed<'a, T> {
pub const fn new(value: &'a T) -> Self {
Self(value)
}
pub const fn into_inner(self) -> &'a T {
self.0
}
#[inline]
pub(crate) fn as_ptr(&self) -> *const T {
self.0 as *const T
}
}
impl<'a, T: ?Sized> Deref for Borrowed<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.0
}
}
#[cfg_attr(
target_pointer_width = "32",
doc = "[Binds](Bind) a [`&str`](str) via [`sqlite3_bind_text`]."
)]
#[cfg_attr(
target_pointer_width = "64",
doc = "[Binds](Bind) a [`&str`](str) via [`sqlite3_bind_text64`]."
)]
impl<'b, 'a: 'b> Bind<'b> for Borrowed<'a, str> {
unsafe fn bind<'c>(self, statement: &Statement<'c>, index: BindIndex) -> Result<()>
where
'c: 'b,
{
#[cfg(target_pointer_width = "32")]
{
use crate::error::{Error, ErrorMessage};
let result = unsafe {
sqlite3_bind_text(
statement.as_ptr(),
index.value(),
self.as_ptr() as *const i8,
self.0.len() as i32,
SQLITE_STATIC,
)
};
match Error::<ErrorMessage>::from_connection(statement, result) {
Some(err) => Err(err),
None => Ok(()),
}
}
#[cfg(target_pointer_width = "64")]
{
use crate::error::{Error, ErrorMessage};
let result = unsafe {
sqlite3_bind_text64(
statement.as_ptr(),
index.value(),
self.as_ptr() as *const i8,
self.0.len() as sqlite3_uint64,
SQLITE_STATIC,
ENCODING_UTF8,
)
};
match Error::<ErrorMessage>::from_connection(statement, result) {
Some(err) => Err(err),
None => Ok(()),
}
}
}
}
#[cfg_attr(
target_pointer_width = "32",
doc = "[Binds](Bind) a [`&[u8]`](primitive@slice) via [`sqlite3_bind_blob`]."
)]
#[cfg_attr(
target_pointer_width = "64",
doc = "[Binds](Bind) a [`&[u8]`](primitive@slice) via [`sqlite3_bind_blob64`]."
)]
impl<'b, 'a: 'b> Bind<'b> for Borrowed<'a, [u8]> {
unsafe fn bind<'c>(self, statement: &Statement<'c>, index: BindIndex) -> Result<()>
where
'c: 'b,
{
#[cfg(target_pointer_width = "32")]
{
use crate::error::{Error, ErrorMessage};
use core::ffi::c_void;
let result = unsafe {
sqlite3_bind_blob(
statement.as_ptr(),
index.value(),
self.as_ptr() as *const c_void,
self.0.len() as i32,
SQLITE_STATIC,
)
};
match Error::<ErrorMessage>::from_connection(statement, result) {
Some(err) => Err(err),
None => Ok(()),
}
}
#[cfg(target_pointer_width = "64")]
{
use crate::error::{Error, ErrorMessage};
use core::ffi::c_void;
let result = unsafe {
sqlite3_bind_blob64(
statement.as_ptr(),
index.value(),
self.as_ptr() as *const c_void,
self.0.len() as sqlite3_uint64,
SQLITE_STATIC,
)
};
match Error::<ErrorMessage>::from_connection(statement, result) {
Some(err) => Err(err),
None => Ok(()),
}
}
}
}
impl<'r> Fetch<'r> for Borrowed<'r, str> {
unsafe fn fetch<'c>(statement: &'r Statement<'c>, column: ColumnIndex) -> Self
where
'c: 'r,
{
let data = unsafe { sqlite3_column_text(statement.as_ptr(), column.value()) };
let len = unsafe { sqlite3_column_bytes(statement.as_ptr(), column.value()) };
let bytes = unsafe { slice::from_raw_parts::<'r, u8>(data, len as usize) };
let text = unsafe { core::str::from_utf8_unchecked(bytes) };
Self(text)
}
}
impl<'r> Fetch<'r> for Borrowed<'r, [u8]> {
unsafe fn fetch<'c>(statement: &'r Statement<'c>, column: ColumnIndex) -> Self
where
'c: 'r,
{
let data = unsafe { sqlite3_column_blob(statement.as_ptr(), column.value()) };
let len = unsafe { sqlite3_column_bytes(statement.as_ptr(), column.value()) };
let bytes = unsafe { slice::from_raw_parts::<'r, u8>(data as *const u8, len as usize) };
Self(bytes)
}
}