Skip to content

Commit 81a792d

Browse files
committed
cleanup scalarfn definition. credit: github.com/asg017/pull/15
1 parent b5c6021 commit 81a792d

File tree

4 files changed

+142
-35
lines changed

4 files changed

+142
-35
lines changed

Cargo.lock

Lines changed: 104 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ libsqlite3-sys = {version="0.26.0", optional=true, features=["bundled"]}
2020
[dev-dependencies]
2121
rusqlite = "0.29.0"
2222
libsqlite3-sys = {version="0.26.0", default-features = false, features=["bundled"]}
23+
rand = "0.8.4"
2324

2425
[features]
2526
static = ["libsqlite3-sys"]

examples/scalar.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,44 @@
11
//! cargo build --example scalar
22
//! sqlite3 :memory: '.read examples/test.sql'
33
4-
use sqlite_loadable::prelude::*;
4+
use rand::Rng;
55
use sqlite_loadable::{api, define_scalar_function, Result};
6+
use sqlite_loadable::{define_scalar_function_with_aux, prelude::*};
67

78
// yo()
89
fn yo(context: *mut sqlite3_context, _values: &[*mut sqlite3_value]) -> Result<()> {
910
api::result_text(context, "yo")?;
1011
Ok(())
1112
}
1213

14+
fn random_int64(
15+
context: *mut sqlite3_context,
16+
_values: &[*mut sqlite3_value],
17+
rng: &mut rand::rngs::ThreadRng,
18+
) -> Result<()> {
19+
let random_int64: i64 = rng.gen();
20+
api::result_int64(context, random_int64);
21+
Ok(())
22+
}
23+
1324
// surround_rs(name)
1425
fn surround(context: *mut sqlite3_context, values: &[*mut sqlite3_value]) -> Result<()> {
15-
let value = api::value_text(values.get(0).expect("1st argument as name"))?;
26+
let value = api::value_text(values.first().expect("1st argument as name"))?;
1627
api::result_text(context, format!("x{}x", value))?;
1728
Ok(())
1829
}
1930

2031
// add_rs(a, b)
2132
fn add(context: *mut sqlite3_context, values: &[*mut sqlite3_value]) -> Result<()> {
22-
let a = api::value_int(values.get(0).expect("1st argument"));
33+
let a = api::value_int(values.first().expect("1st argument"));
2334
let b = api::value_int(values.get(1).expect("2nd argument"));
2435
api::result_int(context, a + b);
2536
Ok(())
2637
}
2738

2839
// connect(seperator, string1, ...)
2940
fn connect(context: *mut sqlite3_context, values: &[*mut sqlite3_value]) -> Result<()> {
30-
let seperator = api::value_text(values.get(0).expect("1st argument"))?;
41+
let seperator = api::value_text(values.first().expect("1st argument"))?;
3142
let strings: Vec<&str> = values
3243
.get(1..)
3344
.expect("more than 1 argument to be given")
@@ -45,5 +56,7 @@ pub fn sqlite3_scalarrs_init(db: *mut sqlite3) -> Result<()> {
4556
define_scalar_function(db, "connect", -1, connect, flags)?;
4657
define_scalar_function(db, "yo_rs", 0, yo, flags)?;
4758
define_scalar_function(db, "add_rs", 2, add, flags)?;
59+
let rng = rand::thread_rng();
60+
define_scalar_function_with_aux(db, "random_int64", 0, random_int64, flags, rng)?;
4861
Ok(())
4962
}

src/scalar.rs

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -136,59 +136,57 @@ where
136136
None,
137137
)
138138
}
139+
type ValueScalarCallbackWithAux<T> =
140+
fn(*mut sqlite3_context, &[*mut sqlite3_value], &mut T) -> Result<()>;
141+
struct ScalarCallbackWithAux<T> {
142+
x_func: ValueScalarCallbackWithAux<T>,
143+
aux: T,
144+
}
139145

140146
/// Defines a new scalar function, but with the added ability to pass in an arbritary
141147
/// application "pointer" as any rust type. Can be accessed in the callback
142148
/// function as the 3rd argument, as a reference.
143149
/// <https://www.sqlite.org/c3ref/create_function.html#:~:text=The%20fifth%20parameter%20is%20an%20arbitrary%20pointer.>
144-
pub fn define_scalar_function_with_aux<F, T>(
150+
pub fn define_scalar_function_with_aux<T>(
145151
db: *mut sqlite3,
146152
name: &str,
147153
num_args: c_int,
148-
x_func: F,
154+
x_func: ValueScalarCallbackWithAux<T>,
149155
func_flags: FunctionFlags,
150156
aux: T,
151-
) -> Result<()>
152-
where
153-
F: Fn(*mut sqlite3_context, &[*mut sqlite3_value], &T) -> Result<()>,
154-
{
155-
let function_pointer: *mut F = Box::into_raw(Box::new(x_func));
156-
let aux_pointer: *mut T = Box::into_raw(Box::new(aux));
157-
let app_pointer = Box::into_raw(Box::new((function_pointer, aux_pointer)));
157+
) -> Result<()> {
158+
let app_pointer = Box::into_raw(Box::new(ScalarCallbackWithAux { x_func, aux }));
158159

159-
unsafe extern "C" fn x_func_wrapper<F, T>(
160+
unsafe extern "C" fn x_func_wrapper<T>(
160161
context: *mut sqlite3_context,
161162
argc: c_int,
162163
argv: *mut *mut sqlite3_value,
163-
) where
164-
F: Fn(*mut sqlite3_context, &[*mut sqlite3_value], &T) -> Result<()>,
165-
{
166-
let x = sqlite3ext_user_data(context).cast::<(*mut F, *mut T)>();
167-
let boxed_function = (*x).0;
168-
let aux = (*x).1;
169-
// .collect slows things waaaay down, so stick with slice for now
164+
) {
165+
let x = sqlite3ext_user_data(context).cast::<ScalarCallbackWithAux<T>>();
170166
let args = slice::from_raw_parts(argv, argc as usize);
171-
let b = Box::from_raw(aux);
172-
match (*boxed_function)(context, args, &*b) {
167+
match ((*x).x_func)(context, args, &mut (*x).aux) {
173168
Ok(()) => (),
174169
Err(e) => {
175170
if api::result_error(context, &e.result_error_message()).is_err() {
176171
api::result_error_code(context, SQLITE_INTERNAL);
177172
}
178173
}
179174
}
180-
Box::into_raw(b);
175+
}
176+
unsafe extern "C" fn destroy<T>(p_app: *mut c_void) {
177+
let callbacks = p_app.cast::<ScalarCallbackWithAux<T>>();
178+
let _ = Box::from_raw(callbacks);
181179
}
182180
create_function_v2(
183181
db,
184182
name,
185183
num_args,
186184
func_flags,
187185
app_pointer.cast::<c_void>(),
188-
Some(x_func_wrapper::<F, T>),
189-
None,
186+
Some(x_func_wrapper::<T>),
190187
None,
191188
None,
189+
Some(destroy::<T>),
192190
)
193191
}
194192

0 commit comments

Comments
 (0)