diff --git a/src/vtab/array.rs b/src/vtab/array.rs index 0d32bd2..f1d793b 100644 --- a/src/vtab/array.rs +++ b/src/vtab/array.rs @@ -27,6 +27,7 @@ //! ``` use std::default::Default; +use std::marker::PhantomData; use std::os::raw::{c_char, c_int, c_void}; use std::rc::Rc; @@ -72,9 +73,9 @@ struct ArrayTab { base: ffi::sqlite3_vtab, } -unsafe impl VTab for ArrayTab { +unsafe impl<'vtab> VTab<'vtab> for ArrayTab { type Aux = (); - type Cursor = ArrayTabCursor; + type Cursor = ArrayTabCursor<'vtab>; fn connect( _: &mut VTabConnection, @@ -118,28 +119,30 @@ unsafe impl VTab for ArrayTab { Ok(()) } - fn open(&self) -> Result { + fn open(&'vtab self) -> Result> { Ok(ArrayTabCursor::new()) } } /// A cursor for the Array virtual table #[repr(C)] -struct ArrayTabCursor { +struct ArrayTabCursor<'vtab> { /// Base class. Must be first base: ffi::sqlite3_vtab_cursor, /// The rowid row_id: i64, /// Pointer to the array of values ("pointer") ptr: Option, + phantom: PhantomData<&'vtab ArrayTab>, } -impl ArrayTabCursor { - fn new() -> ArrayTabCursor { +impl ArrayTabCursor<'_> { + fn new<'vtab>() -> ArrayTabCursor<'vtab> { ArrayTabCursor { base: ffi::sqlite3_vtab_cursor::default(), row_id: 0, ptr: None, + phantom: PhantomData, } } @@ -150,7 +153,7 @@ impl ArrayTabCursor { } } } -unsafe impl VTabCursor for ArrayTabCursor { +unsafe impl VTabCursor for ArrayTabCursor<'_> { fn filter(&mut self, idx_num: c_int, _idx_str: Option<&str>, args: &Values<'_>) -> Result<()> { if idx_num > 0 { self.ptr = args.get_array(0)?; diff --git a/src/vtab/csvtab.rs b/src/vtab/csvtab.rs index 0d8a4c5..21b8131 100644 --- a/src/vtab/csvtab.rs +++ b/src/vtab/csvtab.rs @@ -22,6 +22,7 @@ //! } //! ``` use std::fs::File; +use std::marker::PhantomData; use std::os::raw::c_int; use std::path::Path; use std::str; @@ -95,9 +96,9 @@ impl CSVTab { } } -unsafe impl VTab for CSVTab { +unsafe impl<'vtab> VTab<'vtab> for CSVTab { type Aux = (); - type Cursor = CSVTabCursor; + type Cursor = CSVTabCursor<'vtab>; fn connect( _: &mut VTabConnection, @@ -258,16 +259,16 @@ unsafe impl VTab for CSVTab { Ok(()) } - fn open(&self) -> Result { + fn open(&'vtab self) -> Result> { Ok(CSVTabCursor::new(self.reader()?)) } } -impl CreateVTab for CSVTab {} +impl CreateVTab<'_> for CSVTab {} /// A cursor for the CSV virtual table #[repr(C)] -struct CSVTabCursor { +struct CSVTabCursor<'vtab> { /// Base class. Must be first base: ffi::sqlite3_vtab_cursor, /// The CSV reader object @@ -277,16 +278,18 @@ struct CSVTabCursor { /// Values of the current row cols: csv::StringRecord, eof: bool, + phantom: PhantomData<&'vtab CSVTab>, } -impl CSVTabCursor { - fn new(reader: csv::Reader) -> CSVTabCursor { +impl CSVTabCursor<'_> { + fn new<'vtab>(reader: csv::Reader) -> CSVTabCursor<'vtab> { CSVTabCursor { base: ffi::sqlite3_vtab_cursor::default(), reader, row_number: 0, cols: csv::StringRecord::new(), eof: false, + phantom: PhantomData, } } @@ -296,7 +299,7 @@ impl CSVTabCursor { } } -unsafe impl VTabCursor for CSVTabCursor { +unsafe impl VTabCursor for CSVTabCursor<'_> { // Only a full table scan is supported. So `filter` simply rewinds to // the beginning. fn filter( diff --git a/src/vtab/mod.rs b/src/vtab/mod.rs index bac2c94..dc3bda6 100644 --- a/src/vtab/mod.rs +++ b/src/vtab/mod.rs @@ -61,13 +61,13 @@ use crate::{str_to_cstring, Connection, Error, InnerConnection, Result}; /// /// (See [SQLite doc](https://sqlite.org/c3ref/module.html)) #[repr(transparent)] -pub struct Module { +pub struct Module<'vtab, T: VTab<'vtab>> { base: ffi::sqlite3_module, - phantom: PhantomData, + phantom: PhantomData<&'vtab T>, } -unsafe impl Send for Module {} -unsafe impl Sync for Module {} +unsafe impl<'vtab, T: VTab<'vtab>> Send for Module<'vtab, T> {} +unsafe impl<'vtab, T: VTab<'vtab>> Sync for Module<'vtab, T> {} union ModuleZeroHack { bytes: [u8; std::mem::size_of::()], @@ -87,7 +87,7 @@ const ZERO_MODULE: ffi::sqlite3_module = unsafe { /// `feature = "vtab"` Create a read-only virtual table implementation. /// /// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations). -pub fn read_only_module() -> &'static Module { +pub fn read_only_module<'vtab, T: CreateVTab<'vtab>>() -> &'static Module<'vtab, T> { // The xConnect and xCreate methods do the same thing, but they must be // different so that the virtual table is not an eponymous virtual table. &Module { @@ -118,14 +118,14 @@ pub fn read_only_module() -> &'static Module { xRollbackTo: None, ..ZERO_MODULE }, - phantom: PhantomData::, + phantom: PhantomData::<&'vtab T>, } } /// `feature = "vtab"` Create an eponymous only virtual table implementation. /// /// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations). -pub fn eponymous_only_module() -> &'static Module { +pub fn eponymous_only_module<'vtab, T: VTab<'vtab>>() -> &'static Module<'vtab, T> { // A virtual table is eponymous if its xCreate method is the exact same function // as the xConnect method For eponymous-only virtual tables, the xCreate // method is NULL @@ -157,7 +157,7 @@ pub fn eponymous_only_module() -> &'static Module { xRollbackTo: None, ..ZERO_MODULE }, - phantom: PhantomData::, + phantom: PhantomData::<&'vtab T>, } } @@ -204,7 +204,7 @@ impl VTabConnection { /// ``` /// /// (See [SQLite doc](https://sqlite.org/c3ref/vtab.html)) -pub unsafe trait VTab: Sized { +pub unsafe trait VTab<'vtab>: Sized { /// Client data passed to `Connection::create_module`. type Aux; /// Specific cursor implementation @@ -225,13 +225,13 @@ pub unsafe trait VTab: Sized { /// Create a new cursor used for accessing a virtual table. /// (See [SQLite doc](https://sqlite.org/vtab.html#the_xopen_method)) - fn open(&self) -> Result; + fn open(&'vtab self) -> Result; } /// `feature = "vtab"` Non-eponymous virtual table instance trait. /// /// (See [SQLite doc](https://sqlite.org/c3ref/vtab.html)) -pub trait CreateVTab: VTab { +pub trait CreateVTab<'vtab>: VTab<'vtab> { /// Create a new instance of a virtual table in response to a CREATE VIRTUAL /// TABLE statement. The `db` parameter is a pointer to the SQLite /// database connection that is executing the CREATE VIRTUAL TABLE @@ -607,10 +607,10 @@ impl Connection { /// /// Step 3 of [Creating New Virtual Table /// Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations). - pub fn create_module( + pub fn create_module<'vtab, T: VTab<'vtab>>( &self, module_name: &str, - module: &'static Module, + module: &'static Module<'vtab, T>, aux: Option, ) -> Result<()> { self.db.borrow_mut().create_module(module_name, module, aux) @@ -618,10 +618,10 @@ impl Connection { } impl InnerConnection { - fn create_module( + fn create_module<'vtab, T: VTab<'vtab>>( &mut self, module_name: &str, - module: &'static Module, + module: &'static Module<'vtab, T>, aux: Option, ) -> Result<()> { let c_name = str_to_cstring(module_name)?; @@ -703,7 +703,7 @@ unsafe extern "C" fn free_boxed_value(p: *mut c_void) { let _: Box = Box::from_raw(p as *mut T); } -unsafe extern "C" fn rust_create( +unsafe extern "C" fn rust_create<'vtab, T>( db: *mut ffi::sqlite3, aux: *mut c_void, argc: c_int, @@ -712,7 +712,7 @@ unsafe extern "C" fn rust_create( err_msg: *mut *mut c_char, ) -> c_int where - T: CreateVTab, + T: CreateVTab<'vtab>, { use std::ffi::CStr; @@ -755,7 +755,7 @@ where } } -unsafe extern "C" fn rust_connect( +unsafe extern "C" fn rust_connect<'vtab, T>( db: *mut ffi::sqlite3, aux: *mut c_void, argc: c_int, @@ -764,7 +764,7 @@ unsafe extern "C" fn rust_connect( err_msg: *mut *mut c_char, ) -> c_int where - T: VTab, + T: VTab<'vtab>, { use std::ffi::CStr; @@ -807,12 +807,12 @@ where } } -unsafe extern "C" fn rust_best_index( +unsafe extern "C" fn rust_best_index<'vtab, T>( vtab: *mut ffi::sqlite3_vtab, info: *mut ffi::sqlite3_index_info, ) -> c_int where - T: VTab, + T: VTab<'vtab>, { let vt = vtab as *mut T; let mut idx_info = IndexInfo(info); @@ -831,9 +831,9 @@ where } } -unsafe extern "C" fn rust_disconnect(vtab: *mut ffi::sqlite3_vtab) -> c_int +unsafe extern "C" fn rust_disconnect<'vtab, T>(vtab: *mut ffi::sqlite3_vtab) -> c_int where - T: VTab, + T: VTab<'vtab>, { if vtab.is_null() { return ffi::SQLITE_OK; @@ -843,9 +843,9 @@ where ffi::SQLITE_OK } -unsafe extern "C" fn rust_destroy(vtab: *mut ffi::sqlite3_vtab) -> c_int +unsafe extern "C" fn rust_destroy<'vtab, T>(vtab: *mut ffi::sqlite3_vtab) -> c_int where - T: CreateVTab, + T: CreateVTab<'vtab>, { if vtab.is_null() { return ffi::SQLITE_OK; @@ -869,12 +869,12 @@ where } } -unsafe extern "C" fn rust_open( +unsafe extern "C" fn rust_open<'vtab, T: 'vtab>( vtab: *mut ffi::sqlite3_vtab, pp_cursor: *mut *mut ffi::sqlite3_vtab_cursor, ) -> c_int where - T: VTab, + T: VTab<'vtab>, { let vt = vtab as *mut T; match (*vt).open() { diff --git a/src/vtab/series.rs b/src/vtab/series.rs index dfc8e69..0a129f2 100644 --- a/src/vtab/series.rs +++ b/src/vtab/series.rs @@ -4,6 +4,7 @@ //! "function"](http://www.sqlite.org/cgi/src/finfo?name=ext/misc/series.c): //! https://www.sqlite.org/series.html use std::default::Default; +use std::marker::PhantomData; use std::os::raw::c_int; use crate::ffi; @@ -49,9 +50,9 @@ struct SeriesTab { base: ffi::sqlite3_vtab, } -unsafe impl VTab for SeriesTab { +unsafe impl<'vtab> VTab<'vtab> for SeriesTab { type Aux = (); - type Cursor = SeriesTabCursor; + type Cursor = SeriesTabCursor<'vtab>; fn connect( _: &mut VTabConnection, @@ -151,15 +152,14 @@ unsafe impl VTab for SeriesTab { Ok(()) } - fn open(&self) -> Result { + fn open(&'vtab self) -> Result> { Ok(SeriesTabCursor::new()) } } /// A cursor for the Series virtual table -#[derive(Default)] #[repr(C)] -struct SeriesTabCursor { +struct SeriesTabCursor<'vtab> { /// Base class. Must be first base: ffi::sqlite3_vtab_cursor, /// True to count down rather than up @@ -174,14 +174,24 @@ struct SeriesTabCursor { max_value: i64, /// Increment ("step") step: i64, + phantom: PhantomData<&'vtab SeriesTab>, } -impl SeriesTabCursor { - fn new() -> SeriesTabCursor { - SeriesTabCursor::default() +impl SeriesTabCursor<'_> { + fn new<'vtab>() -> SeriesTabCursor<'vtab> { + SeriesTabCursor { + base: ffi::sqlite3_vtab_cursor::default(), + is_desc: false, + row_id: 0, + value: 0, + min_value: 0, + max_value: 0, + step: 0, + phantom: PhantomData, + } } } -unsafe impl VTabCursor for SeriesTabCursor { +unsafe impl VTabCursor for SeriesTabCursor<'_> { fn filter(&mut self, idx_num: c_int, _idx_str: Option<&str>, args: &Values<'_>) -> Result<()> { let idx_num = QueryPlanFlags::from_bits_truncate(idx_num); let mut i = 0; diff --git a/tests/vtab.rs b/tests/vtab.rs index d42bac6..4b31574 100644 --- a/tests/vtab.rs +++ b/tests/vtab.rs @@ -9,6 +9,7 @@ fn test_dummy_module() { VTabConnection, VTabCursor, Values, }; use rusqlite::{version_number, Connection, Result}; + use std::marker::PhantomData; use std::os::raw::c_int; let module = eponymous_only_module::(); @@ -19,9 +20,9 @@ fn test_dummy_module() { base: sqlite3_vtab, } - unsafe impl VTab for DummyTab { + unsafe impl<'vtab> VTab<'vtab> for DummyTab { type Aux = (); - type Cursor = DummyTabCursor; + type Cursor = DummyTabCursor<'vtab>; fn connect( _: &mut VTabConnection, @@ -39,21 +40,22 @@ fn test_dummy_module() { Ok(()) } - fn open(&self) -> Result { + fn open(&'vtab self) -> Result> { Ok(DummyTabCursor::default()) } } #[derive(Default)] #[repr(C)] - struct DummyTabCursor { + struct DummyTabCursor<'vtab> { /// Base class. Must be first base: sqlite3_vtab_cursor, /// The rowid row_id: i64, + phantom: PhantomData<&'vtab DummyTab>, } - unsafe impl VTabCursor for DummyTabCursor { + unsafe impl VTabCursor for DummyTabCursor<'_> { fn filter( &mut self, _idx_num: c_int,