mirror of
https://github.com/aljazceru/turso.git
synced 2026-01-25 10:54:28 +01:00
262 lines
12 KiB
Rust
262 lines
12 KiB
Rust
use proc_macro::TokenStream;
|
|
use quote::{format_ident, quote};
|
|
use syn::{parse_macro_input, DeriveInput};
|
|
|
|
pub fn derive_vtab_module(input: TokenStream) -> TokenStream {
|
|
let ast = parse_macro_input!(input as DeriveInput);
|
|
let struct_name = &ast.ident;
|
|
|
|
let register_fn_name = format_ident!("register_{}", struct_name);
|
|
let create_fn_name = format_ident!("create_{}", struct_name);
|
|
let open_fn_name = format_ident!("open_{}", struct_name);
|
|
let close_fn_name = format_ident!("close_{}", struct_name);
|
|
let filter_fn_name = format_ident!("filter_{}", struct_name);
|
|
let column_fn_name = format_ident!("column_{}", struct_name);
|
|
let next_fn_name = format_ident!("next_{}", struct_name);
|
|
let eof_fn_name = format_ident!("eof_{}", struct_name);
|
|
let update_fn_name = format_ident!("update_{}", struct_name);
|
|
let rowid_fn_name = format_ident!("rowid_{}", struct_name);
|
|
let destroy_fn_name = format_ident!("destroy_{}", struct_name);
|
|
let best_idx_fn_name = format_ident!("best_idx_{}", struct_name);
|
|
|
|
let expanded = quote! {
|
|
impl #struct_name {
|
|
#[no_mangle]
|
|
unsafe extern "C" fn #create_fn_name(
|
|
argv: *const ::turso_ext::Value, argc: i32
|
|
) -> ::turso_ext::VTabCreateResult {
|
|
let args = if argv.is_null() {
|
|
&Vec::new()
|
|
} else {
|
|
::std::slice::from_raw_parts(argv, argc as usize)
|
|
};
|
|
match <#struct_name as ::turso_ext::VTabModule>::create(&args) {
|
|
Ok((schema, table)) => {
|
|
::turso_ext::VTabCreateResult {
|
|
code: ::turso_ext::ResultCode::OK,
|
|
schema: ::std::ffi::CString::new(schema).unwrap().into_raw(),
|
|
table: ::std::boxed::Box::into_raw(::std::boxed::Box::new(table)) as *const ::std::ffi::c_void,
|
|
}
|
|
},
|
|
Err(e) => {
|
|
::turso_ext::VTabCreateResult {
|
|
code: e,
|
|
schema: ::std::ptr::null(),
|
|
table: ::std::ptr::null(),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
unsafe extern "C" fn #open_fn_name(table: *const ::std::ffi::c_void, conn: *const ::turso_ext::Conn) -> *const ::std::ffi::c_void {
|
|
if table.is_null() {
|
|
return ::std::ptr::null();
|
|
}
|
|
let table = table as *const <#struct_name as ::turso_ext::VTabModule>::Table;
|
|
let table: &<#struct_name as ::turso_ext::VTabModule>::Table = &*table;
|
|
let conn = if conn.is_null() { None } else { Some(::std::sync::Arc::new(::turso_ext::Connection::new(conn)))};
|
|
if let Ok(cursor) = <#struct_name as ::turso_ext::VTabModule>::Table::open(table, conn) {
|
|
return ::std::boxed::Box::into_raw(::std::boxed::Box::new(cursor)) as *const ::std::ffi::c_void;
|
|
} else {
|
|
return ::std::ptr::null();
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
unsafe extern "C" fn #close_fn_name(
|
|
cursor: *const ::std::ffi::c_void
|
|
) -> ::turso_ext::ResultCode {
|
|
if cursor.is_null() {
|
|
return ::turso_ext::ResultCode::Error;
|
|
}
|
|
let cursor = cursor as *mut <<#struct_name as ::turso_ext::VTabModule>::Table as ::turso_ext::VTable>::Cursor;
|
|
let cursor = ::std::boxed::Box::from_raw(cursor);
|
|
<<#struct_name as ::turso_ext::VTabModule>::Table as ::turso_ext::VTable>::Cursor::close(&*cursor)
|
|
}
|
|
|
|
#[no_mangle]
|
|
unsafe extern "C" fn #filter_fn_name(
|
|
cursor: *const ::std::ffi::c_void,
|
|
argc: i32,
|
|
argv: *const ::turso_ext::Value,
|
|
idx_str: *const ::std::ffi::c_char,
|
|
idx_num: i32,
|
|
) -> ::turso_ext::ResultCode {
|
|
if cursor.is_null() {
|
|
return ::turso_ext::ResultCode::Error;
|
|
}
|
|
let cursor = &mut *(cursor as *mut <<#struct_name as ::turso_ext::VTabModule>::Table as ::turso_ext::VTable>::Cursor);
|
|
let args = ::std::slice::from_raw_parts(argv, argc as usize);
|
|
let idx_str = if idx_str.is_null() {
|
|
None
|
|
} else {
|
|
Some((unsafe { ::std::ffi::CStr::from_ptr(idx_str).to_str().unwrap() }, idx_num))
|
|
};
|
|
<<#struct_name as ::turso_ext::VTabModule>::Table as ::turso_ext::VTable>::Cursor::filter(cursor, args, idx_str)
|
|
}
|
|
|
|
#[no_mangle]
|
|
unsafe extern "C" fn #column_fn_name(
|
|
cursor: *const ::std::ffi::c_void,
|
|
idx: u32,
|
|
) -> ::turso_ext::Value {
|
|
if cursor.is_null() {
|
|
return ::turso_ext::Value::error(::turso_ext::ResultCode::Error);
|
|
}
|
|
let cursor = &*(cursor as *const <<#struct_name as ::turso_ext::VTabModule>::Table as ::turso_ext::VTable>::Cursor);
|
|
match <<#struct_name as ::turso_ext::VTabModule>::Table as ::turso_ext::VTable>::Cursor::column(cursor, idx) {
|
|
Ok(val) => val,
|
|
Err(e) => ::turso_ext::Value::error_with_message(e.to_string())
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
unsafe extern "C" fn #next_fn_name(
|
|
cursor: *const ::std::ffi::c_void,
|
|
) -> ::turso_ext::ResultCode {
|
|
if cursor.is_null() {
|
|
return ::turso_ext::ResultCode::Error;
|
|
}
|
|
let cursor = &mut *(cursor as *mut <<#struct_name as ::turso_ext::VTabModule>::Table as ::turso_ext::VTable>::Cursor);
|
|
<<#struct_name as ::turso_ext::VTabModule>::Table as ::turso_ext::VTable>::Cursor::next(cursor)
|
|
}
|
|
|
|
#[no_mangle]
|
|
unsafe extern "C" fn #eof_fn_name(
|
|
cursor: *const ::std::ffi::c_void,
|
|
) -> bool {
|
|
if cursor.is_null() {
|
|
return true;
|
|
}
|
|
let cursor = &*(cursor as *const <<#struct_name as ::turso_ext::VTabModule>::Table as ::turso_ext::VTable>::Cursor);
|
|
<<#struct_name as ::turso_ext::VTabModule>::Table as ::turso_ext::VTable>::Cursor::eof(cursor)
|
|
}
|
|
|
|
#[no_mangle]
|
|
unsafe extern "C" fn #update_fn_name(
|
|
table: *const ::std::ffi::c_void,
|
|
argc: i32,
|
|
argv: *const ::turso_ext::Value,
|
|
p_out_rowid: *mut i64,
|
|
) -> ::turso_ext::ResultCode {
|
|
if table.is_null() {
|
|
return ::turso_ext::ResultCode::Error;
|
|
}
|
|
|
|
let table = &mut *(table as *mut <#struct_name as ::turso_ext::VTabModule>::Table);
|
|
let args = ::std::slice::from_raw_parts(argv, argc as usize);
|
|
|
|
let old_rowid = match args.get(0).map(|v| v.value_type()) {
|
|
Some(::turso_ext::ValueType::Integer) => args.get(0).unwrap().to_integer(),
|
|
_ => None,
|
|
};
|
|
let new_rowid = match args.get(1).map(|v| v.value_type()) {
|
|
Some(::turso_ext::ValueType::Integer) => args.get(1).unwrap().to_integer(),
|
|
_ => None,
|
|
};
|
|
let columns = &args[2..];
|
|
match (old_rowid, new_rowid) {
|
|
// DELETE: old_rowid provided, no new_rowid
|
|
(Some(old), None) => {
|
|
if <#struct_name as VTabModule>::Table::delete(table, old).is_err() {
|
|
return ::turso_ext::ResultCode::Error;
|
|
}
|
|
return ::turso_ext::ResultCode::OK;
|
|
}
|
|
// UPDATE: old_rowid provided and new_rowid may exist
|
|
(Some(old), Some(new)) => {
|
|
if <#struct_name as VTabModule>::Table::update(table, old, &columns).is_err() {
|
|
return ::turso_ext::ResultCode::Error;
|
|
}
|
|
return ::turso_ext::ResultCode::OK;
|
|
}
|
|
// INSERT: no old_rowid (old_rowid = None)
|
|
(None, _) => {
|
|
if let Ok(rowid) = <#struct_name as VTabModule>::Table::insert(table, &columns) {
|
|
if !p_out_rowid.is_null() {
|
|
*p_out_rowid = rowid;
|
|
return ::turso_ext::ResultCode::RowID;
|
|
}
|
|
return ::turso_ext::ResultCode::OK;
|
|
}
|
|
}
|
|
}
|
|
return ::turso_ext::ResultCode::Error;
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn #rowid_fn_name(cursor: *const ::std::ffi::c_void) -> i64 {
|
|
if cursor.is_null() {
|
|
return -1;
|
|
}
|
|
let cursor = &*(cursor as *const <<#struct_name as ::turso_ext::VTabModule>::Table as ::turso_ext::VTable>::Cursor);
|
|
<<#struct_name as ::turso_ext::VTabModule>::Table as ::turso_ext::VTable>::Cursor::rowid(cursor)
|
|
}
|
|
|
|
#[no_mangle]
|
|
unsafe extern "C" fn #destroy_fn_name(
|
|
table: *const ::std::ffi::c_void,
|
|
) -> ::turso_ext::ResultCode {
|
|
if table.is_null() {
|
|
return ::turso_ext::ResultCode::Error;
|
|
}
|
|
|
|
// Take ownership of the table so it can be properly dropped.
|
|
let mut table: ::std::boxed::Box<<#struct_name as ::turso_ext::VTabModule>::Table> =
|
|
::std::boxed::Box::from_raw(table as *mut <#struct_name as ::turso_ext::VTabModule>::Table);
|
|
if <#struct_name as VTabModule>::Table::destroy(&mut *table).is_err() {
|
|
return ::turso_ext::ResultCode::Error;
|
|
}
|
|
|
|
return ::turso_ext::ResultCode::OK;
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn #best_idx_fn_name(
|
|
constraints: *const ::turso_ext::ConstraintInfo,
|
|
n_constraints: i32,
|
|
order_by: *const ::turso_ext::OrderByInfo,
|
|
n_order_by: i32,
|
|
) -> ::turso_ext::ExtIndexInfo {
|
|
let constraints = if n_constraints > 0 { std::slice::from_raw_parts(constraints, n_constraints as usize) } else { &[] };
|
|
let order_by = if n_order_by > 0 { std::slice::from_raw_parts(order_by, n_order_by as usize) } else { &[] };
|
|
match <#struct_name as ::turso_ext::VTabModule>::Table::best_index(constraints, order_by) {
|
|
Ok(index_info) => index_info.to_ffi(),
|
|
Err(e) => ::turso_ext::ExtIndexInfo::error(e),
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn #register_fn_name(
|
|
api: *const ::turso_ext::ExtensionApi
|
|
) -> ::turso_ext::ResultCode {
|
|
if api.is_null() {
|
|
return ::turso_ext::ResultCode::Error;
|
|
}
|
|
let api = &*api;
|
|
let name = <#struct_name as ::turso_ext::VTabModule>::NAME;
|
|
let name_c = ::std::ffi::CString::new(name).unwrap().into_raw() as *const ::std::ffi::c_char;
|
|
let module = ::turso_ext::VTabModuleImpl {
|
|
name: name_c,
|
|
readonly: <#struct_name as ::turso_ext::VTabModule>::READONLY,
|
|
create: Self::#create_fn_name,
|
|
open: Self::#open_fn_name,
|
|
close: Self::#close_fn_name,
|
|
filter: Self::#filter_fn_name,
|
|
column: Self::#column_fn_name,
|
|
next: Self::#next_fn_name,
|
|
eof: Self::#eof_fn_name,
|
|
update: Self::#update_fn_name,
|
|
rowid: Self::#rowid_fn_name,
|
|
destroy: Self::#destroy_fn_name,
|
|
best_idx: Self::#best_idx_fn_name,
|
|
};
|
|
(api.register_vtab_module)(api.ctx, name_c, module, <#struct_name as ::turso_ext::VTabModule>::VTAB_KIND)
|
|
}
|
|
}
|
|
};
|
|
|
|
TokenStream::from(expanded)
|
|
}
|