diff --git a/bindings/wasm/examples/example.js b/bindings/wasm/examples/example.js index e3bba1770..30c2dadf7 100644 --- a/bindings/wasm/examples/example.js +++ b/bindings/wasm/examples/example.js @@ -1,5 +1,5 @@ import { Database } from 'limbo-wasm'; -const db = new Database(':memory:'); +const db = new Database('hello.db'); db.exec("SELECT 'hello, world' AS message"); diff --git a/bindings/wasm/lib.rs b/bindings/wasm/lib.rs index a4b5f2313..475ff22af 100644 --- a/bindings/wasm/lib.rs +++ b/bindings/wasm/lib.rs @@ -1,4 +1,4 @@ -use limbo_core::Result; +use limbo_core::{Result, IO}; use std::rc::Rc; use std::sync::Arc; use wasm_bindgen::prelude::*; @@ -11,9 +11,10 @@ pub struct Database { #[wasm_bindgen] impl Database { #[wasm_bindgen(constructor)] - pub fn new(_path: &str) -> Database { - let io = Arc::new(IO {}); - let page_io = Rc::new(DatabaseStorage {}); + pub fn new(path: &str) -> Database { + let io = Arc::new(PlatformIO { vfs: VFS::new() }); + let file = io.open_file(path).unwrap(); + let page_io = Rc::new(DatabaseStorage::new(file)); let wal = Rc::new(Wal {}); let inner = limbo_core::Database::open(io, page_io, wal).unwrap(); Database { _inner: inner } @@ -23,23 +24,95 @@ impl Database { pub fn exec(&self, _sql: &str) {} } -pub struct IO {} +pub struct File { + vfs: VFS, + fd: i32, +} -impl limbo_core::IO for IO { - fn open_file(&self, _path: &str) -> Result> { - todo!(); - } - - fn run_once(&self) -> Result<()> { - todo!(); +impl File { + fn new(vfs: VFS, fd: i32) -> Self { + File { vfs, fd } } } -pub struct DatabaseStorage {} +impl limbo_core::File for File { + fn lock_file(&self, _exclusive: bool) -> Result<()> { + // TODO + Ok(()) + } + + fn unlock_file(&self) -> Result<()> { + // TODO + Ok(()) + } + + fn pread(&self, pos: usize, c: Rc) -> Result<()> { + let r = match &*c { + limbo_core::Completion::Read(r) => r, + limbo_core::Completion::Write(_) => unreachable!(), + }; + { + let mut buf = r.buf_mut(); + let buf: &mut [u8] = buf.as_mut_slice(); + let nr = self.vfs.pread(self.fd, buf, pos); + assert!(nr >= 0); + } + r.complete(); + Ok(()) + } + + fn pwrite( + &self, + _pos: usize, + _buffer: Rc>, + _c: Rc, + ) -> Result<()> { + todo!() + } +} + +pub struct PlatformIO { + vfs: VFS, +} + +impl limbo_core::IO for PlatformIO { + fn open_file(&self, path: &str) -> Result> { + let fd = self.vfs.open(path); + Ok(Rc::new(File { + vfs: VFS::new(), + fd, + })) + } + + fn run_once(&self) -> Result<()> { + Ok(()) + } +} + +pub struct DatabaseStorage { + file: Rc, +} + +impl DatabaseStorage { + pub fn new(file: Rc) -> Self { + DatabaseStorage { file } + } +} impl limbo_core::DatabaseStorage for DatabaseStorage { - fn read_page(&self, _page_idx: usize, _c: Rc) -> Result<()> { - todo!(); + fn read_page(&self, page_idx: usize, c: Rc) -> Result<()> { + let r = match &(*c) { + limbo_core::Completion::Read(r) => r, + limbo_core::Completion::Write(_) => unreachable!(), + }; + let size = r.buf().len(); + assert!(page_idx > 0); + if !(512..=65536).contains(&size) || size & (size - 1) != 0 { + return Err(limbo_core::LimboError::NotADB); + } + let pos = (page_idx - 1) * size; + self.file.pread(pos, c)?; + Ok(()) } fn write_page( @@ -56,15 +129,15 @@ pub struct Wal {} impl limbo_core::Wal for Wal { fn begin_read_tx(&self) -> Result<()> { - todo!() + Ok(()) } fn end_read_tx(&self) -> Result<()> { - todo!() + Ok(()) } fn find_frame(&self, _page_id: u64) -> Result> { - todo!() + Ok(None) } fn read_frame( @@ -76,7 +149,27 @@ impl limbo_core::Wal for Wal { } } +#[wasm_bindgen(module = "/vfs.js")] +extern "C" { + type VFS; + + #[wasm_bindgen(constructor)] + fn new() -> VFS; + + #[wasm_bindgen(method)] + fn open(this: &VFS, path: &str) -> i32; + + #[wasm_bindgen(method)] + fn close(this: &VFS, fd: i32) -> bool; + + #[wasm_bindgen(method)] + fn pwrite(this: &VFS, fd: i32, buffer: &[u8], offset: usize) -> i32; + + #[wasm_bindgen(method)] + fn pread(this: &VFS, fd: i32, buffer: &mut [u8], offset: usize) -> i32; +} + #[wasm_bindgen(start)] pub fn init() { console_error_panic_hook::set_once(); -} \ No newline at end of file +} diff --git a/bindings/wasm/vfs.js b/bindings/wasm/vfs.js new file mode 100644 index 000000000..64e0326b1 --- /dev/null +++ b/bindings/wasm/vfs.js @@ -0,0 +1,24 @@ +const fs = require('node:fs'); + +class VFS { + constructor() { + } + + open(path) { + return fs.openSync(path, 'r'); + } + + close(fd) { + fs.closeSync(fd); + } + + pread(fd, buffer, offset) { + return fs.readSync(fd, buffer, 0, buffer.length, offset); + } + + pwrite(fd, buffer, offset) { + return fs.writeSync(fd, buffer, 0, buffer.length, offset); + } +} + +module.exports = { VFS }; \ No newline at end of file