sqlite3_ext 0.2.0

Build loadable extensions for SQLite using Rust
Documentation
use super::{
    super::{ffi, value::*},
    *,
};
use std::{
    cmp::Ordering,
    ffi::{c_void, CStr},
    slice,
    str::from_utf8_unchecked,
};

pub unsafe extern "C" fn call_scalar<'a, F>(
    context: *mut ffi::sqlite3_context,
    argc: i32,
    argv: *mut *mut ffi::sqlite3_value,
) where
    F: ScalarFunction<'a>,
{
    let func = &mut *(ffi::sqlite3_user_data(context) as *mut F);
    let ctx = Context::from_ptr(context);
    let args = slice::from_raw_parts_mut(argv as *mut &mut ValueRef, argc as _);
    if let Err(e) = func.call(ctx, args) {
        ctx.set_result(e).unwrap();
    }
}

pub unsafe extern "C" fn aggregate_step<U, F: LegacyAggregateFunction<U>>(
    context: *mut ffi::sqlite3_context,
    argc: i32,
    argv: *mut *mut ffi::sqlite3_value,
) {
    let ac = AggregateContext::from_ptr(context);
    let ctx = Context::from_ptr(context);
    let agg = ac.get_or_insert_with(F::from_user_data).unwrap();
    let args = slice::from_raw_parts_mut(argv as *mut &mut ValueRef, argc as _);
    if let Err(e) = agg.step(ctx, args) {
        ctx.set_result(e).unwrap();
    }
}

pub unsafe extern "C" fn aggregate_final<U, F: LegacyAggregateFunction<U>>(
    context: *mut ffi::sqlite3_context,
) {
    let ac = AggregateContext::<U, F>::from_ptr(context);
    let ctx = Context::from_ptr(context);
    let ret = match ac.take() {
        Some(agg) => agg.value(ctx),
        None => F::default_value(ac.user_data(), ctx),
    };
    if let Err(e) = ret {
        ctx.set_result(e).unwrap();
    }
}

#[cfg(modern_sqlite)]
pub unsafe extern "C" fn aggregate_value<U, F: AggregateFunction<U>>(
    context: *mut ffi::sqlite3_context,
) {
    let ac = AggregateContext::from_ptr(context);
    let ctx = Context::from_ptr(context);
    let agg = ac.get_or_insert_with(F::from_user_data).unwrap();
    if let Err(e) = agg.value(ctx) {
        ctx.set_result(e).unwrap();
    }
}

#[cfg(modern_sqlite)]
pub unsafe extern "C" fn aggregate_inverse<U, F: AggregateFunction<U>>(
    context: *mut ffi::sqlite3_context,
    argc: i32,
    argv: *mut *mut ffi::sqlite3_value,
) {
    let ac = AggregateContext::from_ptr(context);
    let ctx = Context::from_ptr(context);
    let agg = ac.get_or_insert_with(F::from_user_data).unwrap();
    let args = slice::from_raw_parts_mut(argv as *mut &mut ValueRef, argc as _);
    if let Err(e) = agg.inverse(ctx, args) {
        ctx.set_result(e).unwrap();
    }
}

pub unsafe extern "C" fn compare<F: Fn(&str, &str) -> Ordering>(
    func: *mut c_void,
    len_a: i32,
    bytes_a: *const c_void,
    len_b: i32,
    bytes_b: *const c_void,
) -> i32 {
    let func = &*(func as *const F);
    let a = from_utf8_unchecked(slice::from_raw_parts(bytes_a as *const u8, len_a as _));
    let b = from_utf8_unchecked(slice::from_raw_parts(bytes_b as *const u8, len_b as _));
    match func(a, b) {
        Ordering::Less => -1,
        Ordering::Equal => 0,
        Ordering::Greater => 1,
    }
}

pub unsafe extern "C" fn collation_needed<F: Fn(&str)>(
    user_data: *mut c_void,
    _db: *mut ffi::sqlite3,
    _text_rep: i32,
    name: *const i8,
) {
    let func = &*(user_data as *const F);
    let name = match CStr::from_ptr(name).to_str() {
        Ok(x) => x,
        Err(_) => return,
    };
    func(name);
}