From e32bebf7cd49e423c090391ee0aebc5700b091c1 Mon Sep 17 00:00:00 2001 From: James Brown Date: Fri, 9 Oct 2026 13:12:46 -0700 Subject: [PATCH 1/4] bump to rquickjs 0.14 --- libs/test/Cargo.toml | 2 +- libs/test/src/lib.rs | 4 +++- libs/utils/Cargo.toml | 2 +- libs/utils/src/ffi/c_vec.rs | 5 +++-- modules/console/Cargo.toml | 2 +- modules/os/Cargo.toml | 4 ++-- modules/sqlite/Cargo.toml | 2 +- modules/timers/Cargo.toml | 2 +- modules/url/Cargo.toml | 2 +- 9 files changed, 14 insertions(+), 11 deletions(-) diff --git a/libs/test/Cargo.toml b/libs/test/Cargo.toml index a77b3cc..ad488fe 100644 --- a/libs/test/Cargo.toml +++ b/libs/test/Cargo.toml @@ -10,5 +10,5 @@ authors = ["Emile Fugulin "] [dependencies] futures = { version = "0.3" } -rquickjs = { version = ">=0.10,<0.12", features = ["macro", "futures"] } +rquickjs = { version = ">= 0.10, < 0.15", features = ["macro", "futures"] } tokio = { version = "1", features = ["full"] } diff --git a/libs/test/src/lib.rs b/libs/test/src/lib.rs index f6df2c7..f1a6d57 100644 --- a/libs/test/src/lib.rs +++ b/libs/test/src/lib.rs @@ -1,6 +1,5 @@ use rquickjs::{ AsyncContext, AsyncRuntime, CatchResultExt, CaughtError, Ctx, FromJs, Function, Module, Result, - async_with, function::IntoArgs, module::{Evaluated, ModuleDef}, promise::MaybePromise, @@ -15,6 +14,7 @@ where ctx.with(func); } +#[allow(deprecated)] // remove this when we drop support for < 0.13 pub async fn test_async_with(func: F) where F: for<'js> FnOnce(Ctx<'js>) -> std::pin::Pin + 'js>> @@ -23,6 +23,8 @@ where let rt = AsyncRuntime::new().unwrap(); let ctx = AsyncContext::full(&rt).await.unwrap(); + use rquickjs::async_with; + async_with!(ctx => |ctx| { func(ctx).await }) diff --git a/libs/utils/Cargo.toml b/libs/utils/Cargo.toml index 1e9120e..89fb68e 100644 --- a/libs/utils/Cargo.toml +++ b/libs/utils/Cargo.toml @@ -9,4 +9,4 @@ repository = "https://github.com/rquickjs/rquickjs-extra" authors = ["Emile Fugulin "] [dependencies] -rquickjs = { version = ">=0.10,<0.12", features = ["array-buffer"] } +rquickjs = { version = ">= 0.10, < 0.15", features = ["array-buffer"] } diff --git a/libs/utils/src/ffi/c_vec.rs b/libs/utils/src/ffi/c_vec.rs index 1515f33..e213927 100644 --- a/libs/utils/src/ffi/c_vec.rs +++ b/libs/utils/src/ffi/c_vec.rs @@ -13,10 +13,11 @@ pub struct CVec<'js> { #[allow(dead_code)] impl<'js> CVec<'js> { pub fn from_array(array: TypedArray<'js, u8>) -> Result { + let len = array.len(); let raw = array.as_raw().or_throw(array.ctx())?; Ok(Self { - ptr: raw.ptr.as_ptr(), - len: raw.len, + ptr: raw.as_ptr() as *const u8, + len, value: array.into_value(), }) } diff --git a/modules/console/Cargo.toml b/modules/console/Cargo.toml index 6e93477..534045f 100644 --- a/modules/console/Cargo.toml +++ b/modules/console/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Emile Fugulin "] [dependencies] log = { version = "0.4" } -rquickjs = { version = ">=0.10,<0.12", features = ["macro"] } +rquickjs = { version = ">=0.10,<0.15", features = ["macro"] } [dev-dependencies] rquickjs-extra-test = { path = "../../libs/test" } diff --git a/modules/os/Cargo.toml b/modules/os/Cargo.toml index 8d2a4ee..d52777b 100644 --- a/modules/os/Cargo.toml +++ b/modules/os/Cargo.toml @@ -12,7 +12,7 @@ authors = ["Emile Fugulin "] home = "0.5" num_cpus = "1" once_cell = "1" -rquickjs = { version = ">=0.10,<0.12", features = ["macro"] } +rquickjs = { version = ">=0.10,<0.15", features = ["macro"] } rquickjs-extra-utils = { version = "0.2.1", path = "../../libs/utils" } [target.'cfg(unix)'.dependencies] @@ -24,6 +24,6 @@ windows-result = "0.3" windows-version = "0.1" [dev-dependencies] -rquickjs = { version = ">=0.10,<0.12", features = ["futures"] } +rquickjs = { version = "0.14", features = ["futures"] } rquickjs-extra-test = { path = "../../libs/test" } tokio = { version = "1", features = ["full"] } diff --git a/modules/sqlite/Cargo.toml b/modules/sqlite/Cargo.toml index bbb1111..a40ae29 100644 --- a/modules/sqlite/Cargo.toml +++ b/modules/sqlite/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Emile Fugulin "] [dependencies] either = { version = "1" } -rquickjs = { version = ">=0.10,<0.12", features = [ +rquickjs = { version = ">= 0.10, < 0.15", features = [ "array-buffer", "either", "macro", diff --git a/modules/timers/Cargo.toml b/modules/timers/Cargo.toml index bda1c43..2e617a2 100644 --- a/modules/timers/Cargo.toml +++ b/modules/timers/Cargo.toml @@ -9,7 +9,7 @@ authors = ["Emile Fugulin "] [dependencies] log = { version = "0.4" } -rquickjs = { version = ">=0.10,<0.12", features = ["macro", "futures"] } +rquickjs = { version = ">= 0.10, < 0.15", features = ["macro", "futures"] } tokio = { version = "1", features = ["sync", "time", "macros"] } [dev-dependencies] diff --git a/modules/url/Cargo.toml b/modules/url/Cargo.toml index 454db3f..b56854c 100644 --- a/modules/url/Cargo.toml +++ b/modules/url/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Emile Fugulin "] [dependencies] either = { version = "1" } -rquickjs = { version = ">=0.10,<0.12", features = ["either", "macro"] } +rquickjs = { version = ">=0.10,<0.15", features = ["either", "macro"] } [dev-dependencies] rquickjs-extra-test = { path = "../../libs/test" } From 1fb862015eb83791ba85c87e08b0cf255ea5da6b Mon Sep 17 00:00:00 2001 From: Emile Fugulin Date: Sat, 10 Oct 2026 10:50:27 -0400 Subject: [PATCH 2/4] Drop support for earlier versions --- libs/test/Cargo.toml | 2 +- libs/test/src/lib.rs | 14 +-- libs/utils/Cargo.toml | 2 +- modules/console/Cargo.toml | 2 +- modules/os/Cargo.toml | 2 +- modules/os/src/lib.rs | 180 +++++++++++++++----------------- modules/sqlite/Cargo.toml | 2 +- modules/sqlite/src/database.rs | 92 ++++++++-------- modules/sqlite/src/statement.rs | 12 +-- modules/timers/Cargo.toml | 2 +- modules/timers/src/lib.rs | 63 +++++------ modules/url/Cargo.toml | 2 +- 12 files changed, 170 insertions(+), 205 deletions(-) diff --git a/libs/test/Cargo.toml b/libs/test/Cargo.toml index ad488fe..46f9695 100644 --- a/libs/test/Cargo.toml +++ b/libs/test/Cargo.toml @@ -10,5 +10,5 @@ authors = ["Emile Fugulin "] [dependencies] futures = { version = "0.3" } -rquickjs = { version = ">= 0.10, < 0.15", features = ["macro", "futures"] } +rquickjs = { version = "0.14", features = ["macro", "futures"] } tokio = { version = "1", features = ["full"] } diff --git a/libs/test/src/lib.rs b/libs/test/src/lib.rs index f1a6d57..4144249 100644 --- a/libs/test/src/lib.rs +++ b/libs/test/src/lib.rs @@ -14,21 +14,15 @@ where ctx.with(func); } -#[allow(deprecated)] // remove this when we drop support for < 0.13 -pub async fn test_async_with(func: F) +pub async fn test_async_with(func: F) where - F: for<'js> FnOnce(Ctx<'js>) -> std::pin::Pin + 'js>> - + Send, + F: for<'js> AsyncFnOnce(Ctx<'js>) -> R + Send, + R: Send + 'static, { let rt = AsyncRuntime::new().unwrap(); let ctx = AsyncContext::full(&rt).await.unwrap(); - use rquickjs::async_with; - - async_with!(ctx => |ctx| { - func(ctx).await - }) - .await; + ctx.async_with(func).await; } pub async fn call_test<'js, T, A>(ctx: &Ctx<'js>, module: &Module<'js, Evaluated>, args: A) -> T diff --git a/libs/utils/Cargo.toml b/libs/utils/Cargo.toml index 89fb68e..cc227b2 100644 --- a/libs/utils/Cargo.toml +++ b/libs/utils/Cargo.toml @@ -9,4 +9,4 @@ repository = "https://github.com/rquickjs/rquickjs-extra" authors = ["Emile Fugulin "] [dependencies] -rquickjs = { version = ">= 0.10, < 0.15", features = ["array-buffer"] } +rquickjs = { version = "0.14", features = ["array-buffer"] } diff --git a/modules/console/Cargo.toml b/modules/console/Cargo.toml index 534045f..1fc6be1 100644 --- a/modules/console/Cargo.toml +++ b/modules/console/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Emile Fugulin "] [dependencies] log = { version = "0.4" } -rquickjs = { version = ">=0.10,<0.15", features = ["macro"] } +rquickjs = { version = "0.14", features = ["macro"] } [dev-dependencies] rquickjs-extra-test = { path = "../../libs/test" } diff --git a/modules/os/Cargo.toml b/modules/os/Cargo.toml index d52777b..048d612 100644 --- a/modules/os/Cargo.toml +++ b/modules/os/Cargo.toml @@ -12,7 +12,7 @@ authors = ["Emile Fugulin "] home = "0.5" num_cpus = "1" once_cell = "1" -rquickjs = { version = ">=0.10,<0.15", features = ["macro"] } +rquickjs = { version = "0.14", features = ["macro"] } rquickjs-extra-utils = { version = "0.2.1", path = "../../libs/utils" } [target.'cfg(unix)'.dependencies] diff --git a/modules/os/src/lib.rs b/modules/os/src/lib.rs index 81e0eba..9b7d8e9 100644 --- a/modules/os/src/lib.rs +++ b/modules/os/src/lib.rs @@ -84,179 +84,167 @@ mod tests { #[tokio::test] async fn test_type() { - test_async_with(|ctx| { - Box::pin(async move { - ModuleEvaluator::eval_rust::(ctx.clone(), "os") - .await - .unwrap(); - - let module = ModuleEvaluator::eval_js( - ctx.clone(), - "test", - r#" + test_async_with(async |ctx| { + ModuleEvaluator::eval_rust::(ctx.clone(), "os") + .await + .unwrap(); + + let module = ModuleEvaluator::eval_js( + ctx.clone(), + "test", + r#" import { type } from 'os'; export async function test() { return type() } "#, - ) - .await - .unwrap(); + ) + .await + .unwrap(); - let result = call_test::(&ctx, &module, ()).await; + let result = call_test::(&ctx, &module, ()).await; - assert!(result == "Linux" || result == "Windows_NT" || result == "Darwin"); - }) + assert!(result == "Linux" || result == "Windows_NT" || result == "Darwin"); }) .await; } #[tokio::test] async fn test_release() { - test_async_with(|ctx| { - Box::pin(async move { - ModuleEvaluator::eval_rust::(ctx.clone(), "os") - .await - .unwrap(); - - let module = ModuleEvaluator::eval_js( - ctx.clone(), - "test", - r#" + test_async_with(async |ctx| { + ModuleEvaluator::eval_rust::(ctx.clone(), "os") + .await + .unwrap(); + + let module = ModuleEvaluator::eval_js( + ctx.clone(), + "test", + r#" import { release } from 'os'; export async function test() { return release() } "#, - ) - .await - .unwrap(); + ) + .await + .unwrap(); - let result = call_test::(&ctx, &module, ()).await; + let result = call_test::(&ctx, &module, ()).await; - assert!(!result.is_empty()); // Format is platform dependant - }) + assert!(!result.is_empty()); // Format is platform dependant }) .await; } #[tokio::test] async fn test_version() { - test_async_with(|ctx| { - Box::pin(async move { - ModuleEvaluator::eval_rust::(ctx.clone(), "os") - .await - .unwrap(); - - let module = ModuleEvaluator::eval_js( - ctx.clone(), - "test", - r#" + test_async_with(async |ctx| { + ModuleEvaluator::eval_rust::(ctx.clone(), "os") + .await + .unwrap(); + + let module = ModuleEvaluator::eval_js( + ctx.clone(), + "test", + r#" import { version } from 'os'; export async function test() { return version() } "#, - ) - .await - .unwrap(); + ) + .await + .unwrap(); - let result = call_test::(&ctx, &module, ()).await; + let result = call_test::(&ctx, &module, ()).await; - assert!(!result.is_empty()); // Format is platform dependant - }) + assert!(!result.is_empty()); // Format is platform dependant }) .await; } #[tokio::test] async fn test_available_parallelism() { - test_async_with(|ctx| { - Box::pin(async move { - ModuleEvaluator::eval_rust::(ctx.clone(), "os") - .await - .unwrap(); - - let module = ModuleEvaluator::eval_js( - ctx.clone(), - "test", - r#" + test_async_with(async |ctx| { + ModuleEvaluator::eval_rust::(ctx.clone(), "os") + .await + .unwrap(); + + let module = ModuleEvaluator::eval_js( + ctx.clone(), + "test", + r#" import { availableParallelism } from 'os'; export async function test() { return availableParallelism() } "#, - ) - .await - .unwrap(); + ) + .await + .unwrap(); - let result = call_test::(&ctx, &module, ()).await; + let result = call_test::(&ctx, &module, ()).await; - assert!(result > 0); - }) + assert!(result > 0); }) .await; } #[tokio::test] async fn test_eol() { - test_async_with(|ctx| { - Box::pin(async move { - ModuleEvaluator::eval_rust::(ctx.clone(), "os") - .await - .unwrap(); - - let module = ModuleEvaluator::eval_js( - ctx.clone(), - "test", - r#" + test_async_with(async |ctx| { + ModuleEvaluator::eval_rust::(ctx.clone(), "os") + .await + .unwrap(); + + let module = ModuleEvaluator::eval_js( + ctx.clone(), + "test", + r#" import { EOL } from 'os'; export async function test() { return EOL } "#, - ) - .await - .unwrap(); + ) + .await + .unwrap(); - let result = call_test::(&ctx, &module, ()).await; - assert!(result == EOL); - }) + let result = call_test::(&ctx, &module, ()).await; + assert!(result == EOL); }) .await; } #[tokio::test] async fn test_arch() { - test_async_with(|ctx| { - Box::pin(async move { - ModuleEvaluator::eval_rust::(ctx.clone(), "os") - .await - .unwrap(); - - let module = ModuleEvaluator::eval_js( - ctx.clone(), - "test", - r#" + test_async_with(async |ctx| { + ModuleEvaluator::eval_rust::(ctx.clone(), "os") + .await + .unwrap(); + + let module = ModuleEvaluator::eval_js( + ctx.clone(), + "test", + r#" import { arch } from 'os'; export async function test() { return arch() } "#, - ) - .await - .unwrap(); + ) + .await + .unwrap(); - let result = call_test::(&ctx, &module, ()).await; + let result = call_test::(&ctx, &module, ()).await; - assert!(!result.is_empty()); // Format is platform dependant - }) + assert!(!result.is_empty()); // Format is platform dependant }) .await; } diff --git a/modules/sqlite/Cargo.toml b/modules/sqlite/Cargo.toml index a40ae29..2c35b29 100644 --- a/modules/sqlite/Cargo.toml +++ b/modules/sqlite/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Emile Fugulin "] [dependencies] either = { version = "1" } -rquickjs = { version = ">= 0.10, < 0.15", features = [ +rquickjs = { version = "0.14", features = [ "array-buffer", "either", "macro", diff --git a/modules/sqlite/src/database.rs b/modules/sqlite/src/database.rs index a602b08..1f45799 100644 --- a/modules/sqlite/src/database.rs +++ b/modules/sqlite/src/database.rs @@ -47,66 +47,62 @@ mod tests { #[tokio::test] async fn test_database_exec() { - test_async_with(|ctx| { - Box::pin(async move { - ModuleEvaluator::eval_rust::(ctx.clone(), "sqlite") - .await - .unwrap(); - - let module = ModuleEvaluator::eval_js( - ctx.clone(), - "test", - r#" - import { open } from "sqlite"; - - export async function test() { - const db = await open({ inMemory: true }); - await db.exec("CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY, name TEXT);"); - await db.exec("INSERT INTO test (name) VALUES ('test');"); - return "ok"; - } - "#, - ) + test_async_with(async |ctx| { + ModuleEvaluator::eval_rust::(ctx.clone(), "sqlite") .await - .catch(&ctx) .unwrap(); - let result = call_test::(&ctx, &module, ()).await; - assert_eq!(result, "ok"); - }) + let module = ModuleEvaluator::eval_js( + ctx.clone(), + "test", + r#" + import { open } from "sqlite"; + + export async function test() { + const db = await open({ inMemory: true }); + await db.exec("CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY, name TEXT);"); + await db.exec("INSERT INTO test (name) VALUES ('test');"); + return "ok"; + } + "#, + ) + .await + .catch(&ctx) + .unwrap(); + + let result = call_test::(&ctx, &module, ()).await; + assert_eq!(result, "ok"); }) .await; } #[tokio::test] async fn test_database_close() { - test_async_with(|ctx| { - Box::pin(async move { - ModuleEvaluator::eval_rust::(ctx.clone(), "sqlite") - .await - .unwrap(); - - let module = ModuleEvaluator::eval_js( - ctx.clone(), - "test", - r#" - import { open } from "sqlite"; - - export async function test() { - const db = await open({ inMemory: true }); - await db.exec("CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY, name TEXT);"); - await db.close(); - return "ok"; - } - "#, - ) + test_async_with(async |ctx| { + ModuleEvaluator::eval_rust::(ctx.clone(), "sqlite") .await - .catch(&ctx) .unwrap(); - let result = call_test::(&ctx, &module, ()).await; - assert_eq!(result, "ok"); - }) + let module = ModuleEvaluator::eval_js( + ctx.clone(), + "test", + r#" + import { open } from "sqlite"; + + export async function test() { + const db = await open({ inMemory: true }); + await db.exec("CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY, name TEXT);"); + await db.close(); + return "ok"; + } + "#, + ) + .await + .catch(&ctx) + .unwrap(); + + let result = call_test::(&ctx, &module, ()).await; + assert_eq!(result, "ok"); }) .await; } diff --git a/modules/sqlite/src/statement.rs b/modules/sqlite/src/statement.rs index 0594698..880cabc 100644 --- a/modules/sqlite/src/statement.rs +++ b/modules/sqlite/src/statement.rs @@ -106,8 +106,7 @@ mod tests { #[tokio::test] async fn test_statement_all() { - test_async_with(|ctx| { - Box::pin(async move { + test_async_with(async |ctx| { ModuleEvaluator::eval_rust::(ctx.clone(), "sqlite") .await .unwrap(); @@ -135,15 +134,13 @@ mod tests { let result = call_test::(&ctx, &module, ()).await; assert_eq!(result, 2); - }) }) .await; } #[tokio::test] async fn test_statement_get() { - test_async_with(|ctx| { - Box::pin(async move { + test_async_with(async |ctx| { ModuleEvaluator::eval_rust::(ctx.clone(), "sqlite") .await .unwrap(); @@ -170,15 +167,13 @@ mod tests { let result = call_test::(&ctx, &module, ()).await; assert_eq!(result, 1); - }) }) .await; } #[tokio::test] async fn test_statement_run() { - test_async_with(|ctx| { - Box::pin(async move { + test_async_with(async |ctx| { ModuleEvaluator::eval_rust::(ctx.clone(), "sqlite") .await .unwrap(); @@ -204,7 +199,6 @@ mod tests { let result = call_test::(&ctx, &module, ()).await; assert_eq!(result, 2); - }) }) .await; } diff --git a/modules/timers/Cargo.toml b/modules/timers/Cargo.toml index 2e617a2..606b95f 100644 --- a/modules/timers/Cargo.toml +++ b/modules/timers/Cargo.toml @@ -9,7 +9,7 @@ authors = ["Emile Fugulin "] [dependencies] log = { version = "0.4" } -rquickjs = { version = ">= 0.10, < 0.15", features = ["macro", "futures"] } +rquickjs = { version = "0.14", features = ["macro", "futures"] } tokio = { version = "1", features = ["sync", "time", "macros"] } [dev-dependencies] diff --git a/modules/timers/src/lib.rs b/modules/timers/src/lib.rs index 725b6e2..957fa1a 100644 --- a/modules/timers/src/lib.rs +++ b/modules/timers/src/lib.rs @@ -110,7 +110,6 @@ pub fn init(ctx: &Ctx<'_>) -> Result<()> { #[cfg(test)] mod tests { - use futures::FutureExt; use rquickjs::CatchResultExt; use rquickjs::promise::Promise; use rquickjs_extra_test::test_async_with; @@ -119,13 +118,12 @@ mod tests { #[tokio::test] async fn test_set_timeout() { - test_async_with(|ctx| { - async move { - init(&ctx).unwrap(); + test_async_with(async |ctx| { + init(&ctx).unwrap(); - let result = ctx - .eval::( - r#" + let result = ctx + .eval::( + r#" (async function(){ return new Promise((resolve, reject) => { @@ -135,30 +133,27 @@ mod tests { }); })() "#, - ) - .catch(&ctx) - .unwrap() - .into_future::() - .await - .catch(&ctx) - .unwrap(); - - assert_eq!("Hello World", result); - } - .boxed_local() + ) + .catch(&ctx) + .unwrap() + .into_future::() + .await + .catch(&ctx) + .unwrap(); + + assert_eq!("Hello World", result); }) .await } #[tokio::test] async fn test_set_interval() { - test_async_with(|ctx| { - async move { - init(&ctx).unwrap(); + test_async_with(async |ctx| { + init(&ctx).unwrap(); - let result = ctx - .eval::( - r#" + let result = ctx + .eval::( + r#" (async function(){ return new Promise((resolve, reject) => { @@ -171,17 +166,15 @@ mod tests { }); })() "#, - ) - .catch(&ctx) - .unwrap() - .into_future::() - .await - .catch(&ctx) - .unwrap(); - - assert_eq!(3, result); - } - .boxed_local() + ) + .catch(&ctx) + .unwrap() + .into_future::() + .await + .catch(&ctx) + .unwrap(); + + assert_eq!(3, result); }) .await } diff --git a/modules/url/Cargo.toml b/modules/url/Cargo.toml index b56854c..09ab060 100644 --- a/modules/url/Cargo.toml +++ b/modules/url/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Emile Fugulin "] [dependencies] either = { version = "1" } -rquickjs = { version = ">=0.10,<0.15", features = ["either", "macro"] } +rquickjs = { version = "0.14", features = ["either", "macro"] } [dev-dependencies] rquickjs-extra-test = { path = "../../libs/test" } From 21ac1a43ea51f3ed5fc4de534b9a3d87d052d8ad Mon Sep 17 00:00:00 2001 From: Emile Fugulin Date: Sat, 10 Oct 2026 11:02:41 -0400 Subject: [PATCH 3/4] Remove custom cstring implementation --- libs/utils/src/ffi/c_string.rs | 60 ---------------------------------- libs/utils/src/ffi/mod.rs | 2 -- modules/sqlite/src/argument.rs | 13 +++----- 3 files changed, 5 insertions(+), 70 deletions(-) delete mode 100644 libs/utils/src/ffi/c_string.rs diff --git a/libs/utils/src/ffi/c_string.rs b/libs/utils/src/ffi/c_string.rs deleted file mode 100644 index 54f5a97..0000000 --- a/libs/utils/src/ffi/c_string.rs +++ /dev/null @@ -1,60 +0,0 @@ -use std::mem; -use std::{ffi::c_char, slice, str}; - -use rquickjs::{Error, Exception, Result, String, Value, qjs}; - -#[derive(Debug)] -pub struct CString<'js> { - ptr: *const c_char, - len: usize, - value: Value<'js>, -} - -#[allow(dead_code)] -impl<'js> CString<'js> { - pub fn from_string(string: String<'js>) -> Result { - let mut len = mem::MaybeUninit::uninit(); - let ptr = unsafe { - qjs::JS_ToCStringLen( - string.ctx().as_raw().as_ptr(), - len.as_mut_ptr(), - string.as_raw(), - ) - }; - if ptr.is_null() { - // Might not ever happen but I am not 100% sure - // so just incase check it. - return Err(Error::Unknown); - } - let len = unsafe { len.assume_init() }; - Ok(Self { - ptr, - len, - value: string.into_value(), - }) - } - - pub fn as_ptr(&self) -> *const c_char { - self.ptr - } - - pub fn len(&self) -> usize { - self.len - } - - pub fn is_empty(&self) -> bool { - self.len == 0 - } - - pub fn as_str(&self) -> Result<&str> { - let bytes = unsafe { slice::from_raw_parts(self.ptr as *const u8, self.len) }; - str::from_utf8(bytes) - .map_err(|_| Exception::throw_message(self.value.ctx(), "Invalid UTF-8")) - } -} - -impl Drop for CString<'_> { - fn drop(&mut self) { - unsafe { qjs::JS_FreeCString(self.value.ctx().as_raw().as_ptr(), self.ptr) }; - } -} diff --git a/libs/utils/src/ffi/mod.rs b/libs/utils/src/ffi/mod.rs index 12c85c5..bac20bb 100644 --- a/libs/utils/src/ffi/mod.rs +++ b/libs/utils/src/ffi/mod.rs @@ -1,5 +1,3 @@ -pub use self::c_string::CString; pub use self::c_vec::CVec; -mod c_string; mod c_vec; diff --git a/modules/sqlite/src/argument.rs b/modules/sqlite/src/argument.rs index 842a6f2..5b11419 100644 --- a/modules/sqlite/src/argument.rs +++ b/modules/sqlite/src/argument.rs @@ -1,5 +1,5 @@ -use rquickjs::{Ctx, Exception, FromJs, Result, TypedArray}; -use rquickjs_extra_utils::ffi::{CString, CVec}; +use rquickjs::{CString, Ctx, Exception, FromJs, Result}; +use rquickjs_extra_utils::ffi::CVec; use rquickjs_extra_utils::result::ResultExt; use sqlx::Sqlite; use sqlx::query::Query; @@ -27,12 +27,9 @@ impl<'js> FromJs<'js> for Argument<'js> { } else if let Some(string) = value.as_string() { return Ok(Argument::Text(CString::from_string(string.clone())?)); } else if let Some(object) = value.as_object() - && object.as_typed_array::().is_some() + && let Some(typed_array) = object.as_typed_array::() { - // Lifetime issue: https://github.com/DelSkayn/rquickjs/issues/356 - return Ok(Argument::Blob(CVec::from_array( - TypedArray::::from_value(value.clone()).or_throw(ctx)?, - )?)); + return Ok(Argument::Blob(CVec::from_array(typed_array.clone())?)); } Err(Exception::throw_type( ctx, @@ -54,7 +51,7 @@ impl<'js> Argument<'js> { Argument::Null => query.try_bind::>(None).or_throw(ctx), Argument::Integer(int) => query.try_bind(*int).or_throw(ctx), Argument::Real(float) => query.try_bind(*float).or_throw(ctx), - Argument::Text(string) => query.try_bind(string.as_str()?).or_throw(ctx), + Argument::Text(string) => query.try_bind(string.as_str()).or_throw(ctx), Argument::Blob(blob) => query.try_bind(blob.as_slice()).or_throw(ctx), } } From 79e5288bd1d0bcdb4644904c396ef7ca64ea160a Mon Sep 17 00:00:00 2001 From: Emile Fugulin Date: Sat, 10 Oct 2026 11:19:15 -0400 Subject: [PATCH 4/4] Remove unsoundness in Blob Argument --- libs/utils/src/ffi/c_vec.rs | 40 ---------------------------------- libs/utils/src/ffi/mod.rs | 3 --- libs/utils/src/lib.rs | 1 - modules/sqlite/src/argument.rs | 10 ++++++--- 4 files changed, 7 insertions(+), 47 deletions(-) delete mode 100644 libs/utils/src/ffi/c_vec.rs delete mode 100644 libs/utils/src/ffi/mod.rs diff --git a/libs/utils/src/ffi/c_vec.rs b/libs/utils/src/ffi/c_vec.rs deleted file mode 100644 index e213927..0000000 --- a/libs/utils/src/ffi/c_vec.rs +++ /dev/null @@ -1,40 +0,0 @@ -use rquickjs::{Result, TypedArray, Value}; - -use crate::result::ResultExt; - -#[derive(Debug)] -pub struct CVec<'js> { - ptr: *const u8, - len: usize, - #[allow(dead_code)] - value: Value<'js>, -} - -#[allow(dead_code)] -impl<'js> CVec<'js> { - pub fn from_array(array: TypedArray<'js, u8>) -> Result { - let len = array.len(); - let raw = array.as_raw().or_throw(array.ctx())?; - Ok(Self { - ptr: raw.as_ptr() as *const u8, - len, - value: array.into_value(), - }) - } - - pub fn as_ptr(&self) -> *const u8 { - self.ptr - } - - pub fn len(&self) -> usize { - self.len - } - - pub fn is_empty(&self) -> bool { - self.len == 0 - } - - pub fn as_slice(&self) -> &[u8] { - unsafe { std::slice::from_raw_parts(self.ptr, self.len) } - } -} diff --git a/libs/utils/src/ffi/mod.rs b/libs/utils/src/ffi/mod.rs deleted file mode 100644 index bac20bb..0000000 --- a/libs/utils/src/ffi/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub use self::c_vec::CVec; - -mod c_vec; diff --git a/libs/utils/src/lib.rs b/libs/utils/src/lib.rs index 7b16623..6f1915c 100644 --- a/libs/utils/src/lib.rs +++ b/libs/utils/src/lib.rs @@ -1,4 +1,3 @@ -pub mod ffi; pub mod module; pub mod result; pub mod sysinfo; diff --git a/modules/sqlite/src/argument.rs b/modules/sqlite/src/argument.rs index 5b11419..e11c93c 100644 --- a/modules/sqlite/src/argument.rs +++ b/modules/sqlite/src/argument.rs @@ -1,5 +1,4 @@ use rquickjs::{CString, Ctx, Exception, FromJs, Result}; -use rquickjs_extra_utils::ffi::CVec; use rquickjs_extra_utils::result::ResultExt; use sqlx::Sqlite; use sqlx::query::Query; @@ -11,7 +10,7 @@ pub enum Argument<'js> { Integer(i64), Real(f64), Text(CString<'js>), - Blob(CVec<'js>), + Blob(Vec), } impl<'js> FromJs<'js> for Argument<'js> { @@ -29,7 +28,12 @@ impl<'js> FromJs<'js> for Argument<'js> { } else if let Some(object) = value.as_object() && let Some(typed_array) = object.as_typed_array::() { - return Ok(Argument::Blob(CVec::from_array(typed_array.clone())?)); + // SAFETY: We do not yield to the JS engine with the slice held. + let bytes = unsafe { typed_array.as_bytes() }; + let bytes = bytes + .ok_or_else(|| Exception::throw_type(ctx, "Typed array is detached"))? + .to_vec(); + return Ok(Argument::Blob(bytes)); } Err(Exception::throw_type( ctx,