From 20f92fdacf4065cd9776ca156dec8d75be246b40 Mon Sep 17 00:00:00 2001 From: PThorpe92 Date: Thu, 6 Mar 2025 14:40:12 -0500 Subject: [PATCH] Define API for vfs modules extensions --- Cargo.lock | 16 +++- extensions/core/Cargo.toml | 2 + extensions/core/src/lib.rs | 1 + extensions/core/src/vfs_modules.rs | 113 +++++++++++++++++++++++++++++ 4 files changed, 129 insertions(+), 3 deletions(-) create mode 100644 extensions/core/src/vfs_modules.rs diff --git a/Cargo.lock b/Cargo.lock index 6efd9e93a..8b3813db8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -336,16 +336,16 @@ checksum = "18758054972164c3264f7c8386f5fc6da6114cb46b619fd365d4e3b2dc3ae487" [[package]] name = "chrono" -version = "0.4.39" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "wasm-bindgen", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -1043,8 +1043,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi 0.13.3+wasi-0.2.2", + "wasm-bindgen", "windows-targets 0.52.6", ] @@ -1709,6 +1711,8 @@ dependencies = [ name = "limbo_ext" version = "0.0.16" dependencies = [ + "chrono", + "getrandom 0.3.1", "limbo_macros", ] @@ -3614,6 +3618,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-link" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3" + [[package]] name = "windows-sys" version = "0.45.0" diff --git a/extensions/core/Cargo.toml b/extensions/core/Cargo.toml index 1389e39c1..25369e133 100644 --- a/extensions/core/Cargo.toml +++ b/extensions/core/Cargo.toml @@ -12,4 +12,6 @@ core_only = [] static = [] [dependencies] +chrono = "0.4.40" +getrandom = { version = "0.3.1", features = ["wasm_js"] } limbo_macros = { workspace = true } diff --git a/extensions/core/src/lib.rs b/extensions/core/src/lib.rs index 75a779540..f944cedb0 100644 --- a/extensions/core/src/lib.rs +++ b/extensions/core/src/lib.rs @@ -1,4 +1,5 @@ mod types; +mod vfs_modules; pub use limbo_macros::{register_extension, scalar, AggregateDerive, VTabModuleDerive}; use std::{ fmt::Display, diff --git a/extensions/core/src/vfs_modules.rs b/extensions/core/src/vfs_modules.rs new file mode 100644 index 000000000..a95896218 --- /dev/null +++ b/extensions/core/src/vfs_modules.rs @@ -0,0 +1,113 @@ +use crate::{ExtResult, ResultCode}; +use std::ffi::{c_char, c_void}; + +#[cfg(not(target_family = "wasm"))] +pub trait VfsExtension: Default { + const NAME: &'static str; + type File: VfsFile; + fn open_file(&self, path: &str, flags: i32, direct: bool) -> ExtResult; + fn run_once(&self) -> ExtResult<()> { + Ok(()) + } + fn close(&self, _file: Self::File) -> ExtResult<()> { + Ok(()) + } + fn generate_random_number(&self) -> i64 { + let mut buf = [0u8; 8]; + getrandom::fill(&mut buf).unwrap(); + i64::from_ne_bytes(buf) + } + fn get_current_time(&self) -> String { + chrono::Local::now().format("%Y-%m-%d %H:%M:%S").to_string() + } +} + +#[cfg(not(target_family = "wasm"))] +pub trait VfsFile: Sized { + fn lock(&mut self, _exclusive: bool) -> ExtResult<()> { + Ok(()) + } + fn unlock(&self) -> ExtResult<()> { + Ok(()) + } + fn read(&mut self, buf: &mut [u8], count: usize, offset: i64) -> ExtResult; + fn write(&mut self, buf: &[u8], count: usize, offset: i64) -> ExtResult; + fn sync(&self) -> ExtResult<()>; + fn size(&self) -> i64; +} + +#[repr(C)] +pub struct VfsImpl { + pub name: *const c_char, + pub vfs: *const c_void, + pub open: VfsOpen, + pub close: VfsClose, + pub read: VfsRead, + pub write: VfsWrite, + pub sync: VfsSync, + pub lock: VfsLock, + pub unlock: VfsUnlock, + pub size: VfsSize, + pub run_once: VfsRunOnce, + pub current_time: VfsGetCurrentTime, + pub gen_random_number: VfsGenerateRandomNumber, +} + +pub type RegisterVfsFn = + unsafe extern "C" fn(name: *const c_char, vfs: *const VfsImpl) -> ResultCode; + +pub type VfsOpen = unsafe extern "C" fn( + ctx: *const c_void, + path: *const c_char, + flags: i32, + direct: bool, +) -> *const c_void; + +pub type VfsClose = unsafe extern "C" fn(file: *const c_void) -> ResultCode; + +pub type VfsRead = + unsafe extern "C" fn(file: *const c_void, buf: *mut u8, count: usize, offset: i64) -> i32; + +pub type VfsWrite = + unsafe extern "C" fn(file: *const c_void, buf: *const u8, count: usize, offset: i64) -> i32; + +pub type VfsSync = unsafe extern "C" fn(file: *const c_void) -> i32; + +pub type VfsLock = unsafe extern "C" fn(file: *const c_void, exclusive: bool) -> ResultCode; + +pub type VfsUnlock = unsafe extern "C" fn(file: *const c_void) -> ResultCode; + +pub type VfsSize = unsafe extern "C" fn(file: *const c_void) -> i64; + +pub type VfsRunOnce = unsafe extern "C" fn(file: *const c_void) -> ResultCode; + +pub type VfsGetCurrentTime = unsafe extern "C" fn() -> *const c_char; + +pub type VfsGenerateRandomNumber = unsafe extern "C" fn() -> i64; + +#[repr(C)] +pub struct VfsFileImpl { + pub file: *const c_void, + pub vfs: *const VfsImpl, +} + +impl VfsFileImpl { + pub fn new(file: *const c_void, vfs: *const VfsImpl) -> ExtResult { + if file.is_null() || vfs.is_null() { + return Err(ResultCode::Error); + } + Ok(Self { file, vfs }) + } +} + +impl Drop for VfsFileImpl { + fn drop(&mut self) { + if self.vfs.is_null() || self.file.is_null() { + return; + } + let vfs = unsafe { &*self.vfs }; + unsafe { + (vfs.close)(self.file); + } + } +}