Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ jobs:
cd rusqlite
printf "[patch.crates-io]\n" >> Cargo.toml
printf "sqlite-wasm-rs = { path = \"..\" }\n" >> Cargo.toml
printf "libsqlite3-sys = { path = \"libsqlite3-sys\"}\n" >> Cargo.toml
WASM_BINDGEN_TEST_TIMEOUT=60 wasm-pack test --node --features modern-full
test_clippy:
Expand Down
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ include = [
'LICENSE',
]


[patch.crates-io]
sqlite-wasm-rs = { path = "./" }
sqlite-wasm-vfs = { path = "./crates/sqlite-wasm-vfs" }
8 changes: 0 additions & 8 deletions crates/rsqlite-vfs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,5 @@ include.workspace = true
hashbrown = { version = "0.16.1", default-features = false, features = ["default-hasher"] }
thiserror = { version = "2.0.12", default-features = false }

[target.'cfg(not(all(target_family = "wasm", target_os = "unknown")))'.dependencies]
# libsqlite3-sys doesn't compile without features
# see https://github.com/rusqlite/rusqlite/issues/1205
libsqlite3-sys = { version = "0.36.0", default-features = false, features = ["vcpkg", "pkg-config"] }

[target.'cfg(all(target_family = "wasm", target_os = "unknown"))'.dependencies]
wsqlite3-sys = { default-features = false, path = "../wsqlite3-sys" }

[dev-dependencies]
rand = { version = "0.9" }
274 changes: 274 additions & 0 deletions crates/rsqlite-vfs/src/ffi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
pub type sqlite3_int64 = ::core::ffi::c_longlong;
pub type sqlite3_filename = *const ::core::ffi::c_char;
pub type sqlite3_syscall_ptr = ::core::option::Option<unsafe extern "C" fn()>;

pub const SQLITE_CANTOPEN: i32 = 14;
pub const SQLITE_ERROR: i32 = 1;
pub const SQLITE_IOERR: i32 = 10;
pub const SQLITE_IOERR_SHORT_READ: i32 = 522;
pub const SQLITE_IOERR_DELETE: i32 = 2570;
pub const SQLITE_OK: i32 = 0;
pub const SQLITE_OPEN_DELETEONCLOSE: i32 = 8;
pub const SQLITE_OPEN_MAIN_DB: i32 = 256;
pub const SQLITE_OPEN_READWRITE: i32 = 2;
pub const SQLITE_OPEN_CREATE: i32 = 4;
pub const SQLITE_NOTFOUND: i32 = 12;

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct sqlite3_file {
pub pMethods: *const sqlite3_io_methods,
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct sqlite3_io_methods {
pub iVersion: ::core::ffi::c_int,
pub xClose: ::core::option::Option<
unsafe extern "C" fn(arg1: *mut sqlite3_file) -> ::core::ffi::c_int,
>,
pub xRead: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_file,
arg2: *mut ::core::ffi::c_void,
iAmt: ::core::ffi::c_int,
iOfst: sqlite3_int64,
) -> ::core::ffi::c_int,
>,
pub xWrite: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_file,
arg2: *const ::core::ffi::c_void,
iAmt: ::core::ffi::c_int,
iOfst: sqlite3_int64,
) -> ::core::ffi::c_int,
>,
pub xTruncate: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_file,
size: sqlite3_int64,
) -> ::core::ffi::c_int,
>,
pub xSync: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_file,
flags: ::core::ffi::c_int,
) -> ::core::ffi::c_int,
>,
pub xFileSize: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_file,
pSize: *mut sqlite3_int64,
) -> ::core::ffi::c_int,
>,
pub xLock: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_file,
arg2: ::core::ffi::c_int,
) -> ::core::ffi::c_int,
>,
pub xUnlock: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_file,
arg2: ::core::ffi::c_int,
) -> ::core::ffi::c_int,
>,
pub xCheckReservedLock: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_file,
pResOut: *mut ::core::ffi::c_int,
) -> ::core::ffi::c_int,
>,
pub xFileControl: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_file,
op: ::core::ffi::c_int,
pArg: *mut ::core::ffi::c_void,
) -> ::core::ffi::c_int,
>,
pub xSectorSize: ::core::option::Option<
unsafe extern "C" fn(arg1: *mut sqlite3_file) -> ::core::ffi::c_int,
>,
pub xDeviceCharacteristics: ::core::option::Option<
unsafe extern "C" fn(arg1: *mut sqlite3_file) -> ::core::ffi::c_int,
>,
pub xShmMap: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_file,
iPg: ::core::ffi::c_int,
pgsz: ::core::ffi::c_int,
arg2: ::core::ffi::c_int,
arg3: *mut *mut ::core::ffi::c_void,
) -> ::core::ffi::c_int,
>,
pub xShmLock: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_file,
offset: ::core::ffi::c_int,
n: ::core::ffi::c_int,
flags: ::core::ffi::c_int,
) -> ::core::ffi::c_int,
>,
pub xShmBarrier: ::core::option::Option<
unsafe extern "C" fn(arg1: *mut sqlite3_file),
>,
pub xShmUnmap: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_file,
deleteFlag: ::core::ffi::c_int,
) -> ::core::ffi::c_int,
>,
pub xFetch: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_file,
iOfst: sqlite3_int64,
iAmt: ::core::ffi::c_int,
pp: *mut *mut ::core::ffi::c_void,
) -> ::core::ffi::c_int,
>,
pub xUnfetch: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_file,
iOfst: sqlite3_int64,
p: *mut ::core::ffi::c_void,
) -> ::core::ffi::c_int,
>,
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct sqlite3_vfs {
pub iVersion: ::core::ffi::c_int,
pub szOsFile: ::core::ffi::c_int,
pub mxPathname: ::core::ffi::c_int,
pub pNext: *mut sqlite3_vfs,
pub zName: *const ::core::ffi::c_char,
pub pAppData: *mut ::core::ffi::c_void,
pub xOpen: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_vfs,
zName: sqlite3_filename,
arg2: *mut sqlite3_file,
flags: ::core::ffi::c_int,
pOutFlags: *mut ::core::ffi::c_int,
) -> ::core::ffi::c_int,
>,
pub xDelete: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_vfs,
zName: *const ::core::ffi::c_char,
syncDir: ::core::ffi::c_int,
) -> ::core::ffi::c_int,
>,
pub xAccess: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_vfs,
zName: *const ::core::ffi::c_char,
flags: ::core::ffi::c_int,
pResOut: *mut ::core::ffi::c_int,
) -> ::core::ffi::c_int,
>,
pub xFullPathname: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_vfs,
zName: *const ::core::ffi::c_char,
nOut: ::core::ffi::c_int,
zOut: *mut ::core::ffi::c_char,
) -> ::core::ffi::c_int,
>,
pub xDlOpen: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_vfs,
zFilename: *const ::core::ffi::c_char,
) -> *mut ::core::ffi::c_void,
>,
pub xDlError: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_vfs,
nByte: ::core::ffi::c_int,
zErrMsg: *mut ::core::ffi::c_char,
),
>,
pub xDlSym: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_vfs,
arg2: *mut ::core::ffi::c_void,
zSymbol: *const ::core::ffi::c_char,
) -> ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_vfs,
arg2: *mut ::core::ffi::c_void,
zSymbol: *const ::core::ffi::c_char,
),
>,
>,
pub xDlClose: ::core::option::Option<
unsafe extern "C" fn(arg1: *mut sqlite3_vfs, arg2: *mut ::core::ffi::c_void),
>,
pub xRandomness: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_vfs,
nByte: ::core::ffi::c_int,
zOut: *mut ::core::ffi::c_char,
) -> ::core::ffi::c_int,
>,
pub xSleep: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_vfs,
microseconds: ::core::ffi::c_int,
) -> ::core::ffi::c_int,
>,
pub xCurrentTime: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_vfs,
arg2: *mut f64,
) -> ::core::ffi::c_int,
>,
pub xGetLastError: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_vfs,
arg2: ::core::ffi::c_int,
arg3: *mut ::core::ffi::c_char,
) -> ::core::ffi::c_int,
>,
pub xCurrentTimeInt64: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_vfs,
arg2: *mut sqlite3_int64,
) -> ::core::ffi::c_int,
>,
pub xSetSystemCall: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_vfs,
zName: *const ::core::ffi::c_char,
arg2: sqlite3_syscall_ptr,
) -> ::core::ffi::c_int,
>,
pub xGetSystemCall: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_vfs,
zName: *const ::core::ffi::c_char,
) -> sqlite3_syscall_ptr,
>,
pub xNextSystemCall: ::core::option::Option<
unsafe extern "C" fn(
arg1: *mut sqlite3_vfs,
zName: *const ::core::ffi::c_char,
) -> *const ::core::ffi::c_char,
>,
}

unsafe extern "C" {
pub fn sqlite3_vfs_find(zVfsName: *const ::core::ffi::c_char) -> *mut sqlite3_vfs;
}

unsafe extern "C" {
pub fn sqlite3_vfs_register(
arg1: *mut sqlite3_vfs,
makeDflt: ::core::ffi::c_int,
) -> ::core::ffi::c_int;
}

unsafe extern "C" {
pub fn sqlite3_vfs_unregister(arg1: *mut sqlite3_vfs) -> ::core::ffi::c_int;
}
55 changes: 27 additions & 28 deletions crates/rsqlite-vfs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,22 @@
//! This crate also contains a simple operating system independent memvfs implementation
#![no_std]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]

extern crate alloc;

#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
extern crate libsqlite3_sys as bindings;
#[cfg(all(target_family = "wasm", target_os = "unknown"))]
extern crate wsqlite3_sys as bindings;

use self::bindings::*;

// libsqlite3-sys misses this type
#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
#[allow(non_camel_case_types)]
type sqlite3_filename = *const ::core::ffi::c_char;
/// sqlite3 types to implement VFS.
#[rustfmt::skip]
pub mod ffi;
pub mod memvfs;

use alloc::string::String;
use alloc::vec::Vec;
use alloc::{boxed::Box, ffi::CString};
use alloc::{format, vec};
use core::time::Duration;
use core::{cell::RefCell, ffi::CStr, ops::Deref};

pub mod memvfs;
use ffi::*;

/// A macro to return a specific SQLite error code if a condition is true.
///
Expand Down Expand Up @@ -456,6 +449,13 @@ pub trait VfsStore<File, AppData> {
) -> VfsResult<i32>;
}

/// Platform implementation
pub trait OsCallback {
fn sleep(dur: Duration);
fn random(buf: &mut [u8]);
fn epoch_timestamp_in_ms() -> i64;
}

/// A trait that abstracts the `sqlite3_vfs` struct, allowing for a more idiomatic Rust implementation.
#[allow(clippy::missing_safety_doc)]
pub trait SQLiteVfs<IO: SQLiteIoMethods> {
Expand Down Expand Up @@ -1056,12 +1056,12 @@ pub mod test_suite {
}
}

#[cfg(all(test, target_arch = "wasm32"))]
#[cfg(test)]
mod tests {
use super::{MemChunksFile, VfsFile};
use wasm_bindgen_test::wasm_bindgen_test;
use crate::random_name;
use crate::{MemChunksFile, VfsFile};

#[wasm_bindgen_test]
#[test]
fn test_chunks_file() {
let mut file = MemChunksFile::new(512);
file.write(&[], 0).unwrap();
Expand Down Expand Up @@ -1109,17 +1109,16 @@ mod tests {
assert!(file.size().unwrap() == 0);
assert!(file.chunks.len() == 0);
}
}

#[cfg(not(all(test, target_arch = "wasm32")))]
#[test]
fn random_name_is_valid() {
fn random(buf: &mut [u8]) {
rand::fill(buf);
#[test]
fn random_name_is_valid() {
fn random(buf: &mut [u8]) {
rand::fill(buf);
}
let name_1 = random_name(random);
let name_2 = random_name(random);
assert!(name_1.is_ascii(), "Expected an ascii-name: `{name_1}`");
assert!(name_2.is_ascii(), "Expected an ascii-name: `{name_2}`");
assert_ne!(name_1, name_2);
}
let name_1 = random_name(random);
let name_2 = random_name(random);
assert!(name_1.is_ascii(), "Expected an ascii-name: `{name_1}`");
assert!(name_2.is_ascii(), "Expected an ascii-name: `{name_2}`");
assert_ne!(name_1, name_2);
}
Loading