diff --git a/bindings/go/rs_src/lib.rs b/bindings/go/rs_src/lib.rs index 6ef640580..a6068732a 100644 --- a/bindings/go/rs_src/lib.rs +++ b/bindings/go/rs_src/lib.rs @@ -2,11 +2,10 @@ mod rows; #[allow(dead_code)] mod statement; mod types; -use limbo_core::{Connection, Database, LimboError}; +use limbo_core::{Connection, Database, LimboError, IO}; use std::{ ffi::{c_char, c_void}, rc::Rc, - str::FromStr, sync::Arc, }; @@ -14,6 +13,7 @@ use std::{ /// Safe to be called from Go with null terminated DSN string. /// performs null check on the path. #[no_mangle] +#[allow(clippy::arc_with_non_send_sync)] pub unsafe extern "C" fn db_open(path: *const c_char) -> *mut c_void { if path.is_null() { println!("Path is null"); @@ -21,21 +21,23 @@ pub unsafe extern "C" fn db_open(path: *const c_char) -> *mut c_void { } let path = unsafe { std::ffi::CStr::from_ptr(path) }; let path = path.to_str().unwrap(); - let db_options = parse_query_str(path); - if let Ok(io) = get_io(&db_options.path) { - let db = Database::open_file(io.clone(), &db_options.path.to_string()); - match db { - Ok(db) => { - let conn = db.connect(); - return LimboConn::new(conn, io).to_ptr(); - } - Err(e) => { - println!("Error opening database: {}", e); - return std::ptr::null_mut(); - } - }; + let io: Arc = match path { + p if p.contains(":memory:") => { + Arc::new(limbo_core::MemoryIO::new().expect("Failed to create IO")) + } + _ => Arc::new(limbo_core::PlatformIO::new().expect("Failed to create IO")), + }; + let db = Database::open_file(io.clone(), path); + match db { + Ok(db) => { + let conn = db.connect(); + LimboConn::new(conn, io).to_ptr() + } + Err(e) => { + eprintln!("Error: {}", e); + std::ptr::null_mut() + } } - std::ptr::null_mut() } #[allow(dead_code)] @@ -45,7 +47,7 @@ struct LimboConn { err: Option, } -impl<'conn> LimboConn { +impl LimboConn { fn new(conn: Rc, io: Arc) -> Self { LimboConn { conn, @@ -59,7 +61,7 @@ impl<'conn> LimboConn { Box::into_raw(Box::new(self)) as *mut c_void } - fn from_ptr(ptr: *mut c_void) -> &'conn mut LimboConn { + fn from_ptr(ptr: *mut c_void) -> &'static mut LimboConn { if ptr.is_null() { panic!("Null pointer"); } @@ -98,133 +100,3 @@ pub unsafe extern "C" fn db_close(db: *mut c_void) { let _ = unsafe { Box::from_raw(db as *mut LimboConn) }; } } - -#[allow(clippy::arc_with_non_send_sync)] -fn get_io(db_location: &DbType) -> Result, LimboError> { - Ok(match db_location { - DbType::Memory => Arc::new(limbo_core::MemoryIO::new()?), - _ => { - return Ok(Arc::new(limbo_core::PlatformIO::new()?)); - } - }) -} - -#[allow(dead_code)] -struct DbOptions { - path: DbType, - params: Parameters, -} - -#[derive(Default, Debug, Clone)] -enum DbType { - File(String), - #[default] - Memory, -} - -impl std::fmt::Display for DbType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - DbType::File(path) => write!(f, "{}", path), - DbType::Memory => write!(f, ":memory:"), - } - } -} - -#[derive(Debug, Clone, Default)] -struct Parameters { - mode: Mode, - cache: Option, - vfs: Option, - nolock: bool, - immutable: bool, - modeof: Option, -} - -impl FromStr for Parameters { - type Err = (); - fn from_str(s: &str) -> Result { - if !s.contains('?') { - return Ok(Parameters::default()); - } - let mut params = Parameters::default(); - for param in s.split('?').nth(1).unwrap().split('&') { - let mut kv = param.split('='); - match kv.next() { - Some("mode") => params.mode = kv.next().unwrap().parse().unwrap(), - Some("cache") => params.cache = Some(kv.next().unwrap().parse().unwrap()), - Some("vfs") => params.vfs = Some(kv.next().unwrap().to_string()), - Some("nolock") => params.nolock = true, - Some("immutable") => params.immutable = true, - Some("modeof") => params.modeof = Some(kv.next().unwrap().to_string()), - _ => {} - } - } - Ok(params) - } -} - -#[derive(Default, Debug, Clone, Copy)] -enum Cache { - Shared, - #[default] - Private, -} - -impl FromStr for Cache { - type Err = (); - fn from_str(s: &str) -> Result { - match s { - "shared" => Ok(Cache::Shared), - _ => Ok(Cache::Private), - } - } -} - -#[allow(clippy::enum_variant_names)] -#[derive(Default, Debug, Clone, Copy)] -enum Mode { - ReadOnly, - ReadWrite, - #[default] - ReadWriteCreate, -} - -impl FromStr for Mode { - type Err = (); - fn from_str(s: &str) -> Result { - match s { - "readonly" | "ro" => Ok(Mode::ReadOnly), - "readwrite" | "rw" => Ok(Mode::ReadWrite), - "readwritecreate" | "rwc" => Ok(Mode::ReadWriteCreate), - _ => Ok(Mode::default()), - } - } -} - -// At this point we don't have configurable parameters but many -// DSN's are going to have query parameters -fn parse_query_str(mut path: &str) -> DbOptions { - if path == ":memory:" { - return DbOptions { - path: DbType::Memory, - params: Parameters::default(), - }; - } - if path.starts_with("sqlite://") { - path = &path[10..]; - } - if path.contains('?') { - let parameters = Parameters::from_str(path).unwrap(); - let path = &path[..path.find('?').unwrap()]; - DbOptions { - path: DbType::File(path.to_string()), - params: parameters, - } - } else { - DbOptions { - path: DbType::File(path.to_string()), - params: Parameters::default(), - } - } -}