-
Notifications
You must be signed in to change notification settings - Fork 210
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #695 from psarna/wasistub
Support compiling libSQL to Wasm with virtual WAL
- Loading branch information
Showing
8 changed files
with
648 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
Cargo.lock | ||
target/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
[package] | ||
name = "libsql-wasi-demo" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
anyhow = "1.0.75" | ||
rand = "0.8.5" | ||
tracing = "0.1.40" | ||
tracing-subscriber = "0.3.18" | ||
wasmtime = "15.0.0" | ||
wasmtime-wasi = "15.0.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
pub mod memory; | ||
mod vfs; | ||
|
||
type State = WasiCtx; | ||
|
||
use anyhow::Context; | ||
use wasmtime::{Engine, Linker, Module, Store}; | ||
use wasmtime_wasi::{WasiCtx, WasiCtxBuilder}; | ||
|
||
fn main() -> anyhow::Result<()> { | ||
tracing_subscriber::fmt::try_init().ok(); | ||
let engine = Engine::default(); | ||
|
||
let libsql_module = Module::from_file(&engine, "../../libsql.wasm")?; | ||
|
||
let mut linker = Linker::new(&engine); | ||
vfs::link(&mut linker)?; | ||
wasmtime_wasi::add_to_linker(&mut linker, |s| s)?; | ||
|
||
let wasi = WasiCtxBuilder::new() | ||
.inherit_stdio() | ||
.inherit_args()? | ||
.build(); | ||
|
||
let mut store = Store::new(&engine, wasi); | ||
let instance = linker.instantiate(&mut store, &libsql_module)?; | ||
|
||
let malloc = instance.get_typed_func::<i32, i32>(&mut store, "malloc")?; | ||
let free = instance.get_typed_func::<i32, ()>(&mut store, "free")?; | ||
|
||
let memory = instance | ||
.get_memory(&mut store, "memory") | ||
.context("memory export not found")?; | ||
|
||
let db_path = malloc.call(&mut store, 16)?; | ||
memory.write(&mut store, db_path as usize, b"/tmp/wasm-demo.db\0")?; | ||
|
||
let libsql_wasi_init = instance.get_typed_func::<(), ()>(&mut store, "libsql_wasi_init")?; | ||
let open_func = instance.get_typed_func::<i32, i32>(&mut store, "libsql_wasi_open_db")?; | ||
let exec_func = instance.get_typed_func::<(i32, i32), i32>(&mut store, "libsql_wasi_exec")?; | ||
let close_func = instance.get_typed_func::<i32, i32>(&mut store, "sqlite3_close")?; | ||
|
||
libsql_wasi_init.call(&mut store, ())?; | ||
let db = open_func.call(&mut store, db_path)?; | ||
|
||
let sql = malloc.call(&mut store, 64)?; | ||
memory.write(&mut store, sql as usize, b"PRAGMA journal_mode=WAL;\0")?; | ||
let rc = exec_func.call(&mut store, (db, sql))?; | ||
free.call(&mut store, sql)?; | ||
if rc != 0 { | ||
anyhow::bail!("Failed to execute SQL"); | ||
} | ||
|
||
let sql = malloc.call(&mut store, 64)?; | ||
memory.write( | ||
&mut store, | ||
sql as usize, | ||
b"CREATE TABLE testme(id, v1, v2);\0", | ||
)?; | ||
let rc = exec_func.call(&mut store, (db, sql))?; | ||
free.call(&mut store, sql)?; | ||
|
||
let _ = close_func.call(&mut store, db)?; | ||
free.call(&mut store, db_path)?; | ||
|
||
println!("rc: {rc}"); | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
// Shamelessly stolen from Honza - thx man!!! | ||
|
||
use anyhow::{bail, ensure, Context as _, Result}; | ||
|
||
pub type Ptr = i32; | ||
|
||
pub fn slice(memory: &[u8], ptr: Ptr, len: usize) -> Result<&[u8]> { | ||
let ptr = ptr as usize; | ||
ensure!(ptr != 0 && ptr <= memory.len(), "Invalid pointer"); | ||
ensure!(ptr + len <= memory.len(), "Invalid pointer and length"); | ||
Ok(&memory[ptr..][..len]) | ||
} | ||
|
||
pub fn slice_mut(memory: &mut [u8], ptr: Ptr, len: usize) -> Result<&mut [u8]> { | ||
let ptr = ptr as usize; | ||
ensure!(ptr != 0 && ptr <= memory.len(), "Invalid pointer"); | ||
ensure!(ptr + len <= memory.len(), "Invalid pointer and length"); | ||
Ok(&mut memory[ptr..][..len]) | ||
} | ||
|
||
pub fn read_vec(memory: &[u8], ptr: Ptr, len: usize) -> Result<Vec<u8>> { | ||
slice(memory, ptr, len).map(|slice| slice.to_vec()) | ||
} | ||
|
||
pub fn read_cstr(memory: &[u8], cstr_ptr: Ptr) -> Result<String> { | ||
let Some(data) = read_cstr_bytes(memory, cstr_ptr) else { | ||
bail!("Invalid pointer to C string") | ||
}; | ||
String::from_utf8(data).context("Invalid data in C string") | ||
} | ||
|
||
pub fn read_cstr_or_null(memory: &[u8], cstr_ptr: Ptr) -> Result<Option<String>> { | ||
if cstr_ptr != 0 { | ||
read_cstr(memory, cstr_ptr).map(Some) | ||
} else { | ||
Ok(None) | ||
} | ||
} | ||
|
||
pub fn read_cstr_lossy(memory: &[u8], cstr_ptr: Ptr) -> String { | ||
match read_cstr_bytes(memory, cstr_ptr) { | ||
Some(data) => match String::from_utf8(data) { | ||
Ok(string) => string, | ||
Err(err) => String::from_utf8_lossy(err.as_bytes()).into_owned(), | ||
}, | ||
None => String::new(), | ||
} | ||
} | ||
|
||
pub fn read_cstr_bytes(memory: &[u8], cstr_ptr: Ptr) -> Option<Vec<u8>> { | ||
let cstr_ptr = cstr_ptr as usize; | ||
if cstr_ptr == 0 || cstr_ptr >= memory.len() { | ||
return None; | ||
} | ||
|
||
let data = &memory[cstr_ptr..]; | ||
let mut strlen = 0; | ||
loop { | ||
match data.get(strlen) { | ||
None => return None, | ||
Some(0) => break, | ||
Some(_) => strlen += 1, | ||
} | ||
} | ||
|
||
Some(data[..strlen].to_vec()) | ||
} |
Oops, something went wrong.