diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs index 366700a9e..06f268f90 100644 --- a/bindings/rust/src/lib.rs +++ b/bindings/rust/src/lib.rs @@ -1,17 +1,20 @@ pub mod params; -mod value; +pub mod value; + +pub use value::Value; pub use params::params_from_iter; use crate::params::*; -use crate::value::*; use std::rc::Rc; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; #[derive(Debug, thiserror::Error)] pub enum Error { #[error("SQL conversion failure: `{0}`")] ToSqlConversionFailure(BoxError), + #[error("Mutex lock error: {0}")] + MutexError(String), } impl From for Error { @@ -51,17 +54,35 @@ pub struct Database { inner: Arc, } +unsafe impl Send for Database {} +unsafe impl Sync for Database {} + impl Database { pub fn connect(&self) -> Result { let conn = self.inner.connect(); - Ok(Connection { inner: conn }) + #[allow(clippy::arc_with_non_send_sync)] + let connection = Connection { + inner: Arc::new(Mutex::new(conn)), + }; + Ok(connection) } } pub struct Connection { - inner: Rc, + inner: Arc>>, } +impl Clone for Connection { + fn clone(&self) -> Self { + Self { + inner: Arc::clone(&self.inner), + } + } +} + +unsafe impl Send for Connection {} +unsafe impl Sync for Connection {} + impl Connection { pub async fn query(&self, sql: &str, params: impl IntoParams) -> Result { let mut stmt = self.prepare(sql).await?; @@ -74,21 +95,40 @@ impl Connection { } pub async fn prepare(&self, sql: &str) -> Result { - let stmt = self.inner.prepare(sql)?; - Ok(Statement { - _inner: Rc::new(stmt), - }) + let conn = self + .inner + .lock() + .map_err(|e| Error::MutexError(e.to_string()))?; + + let stmt = conn.prepare(sql)?; + + #[allow(clippy::arc_with_non_send_sync)] + let statement = Statement { + inner: Arc::new(Mutex::new(stmt)), + }; + Ok(statement) } } pub struct Statement { - _inner: Rc, + inner: Arc>, } +unsafe impl Send for Statement {} +unsafe impl Sync for Statement {} + impl Statement { pub async fn query(&mut self, params: impl IntoParams) -> Result { - let _params = params.into_params()?; - todo!(); + let params = params.into_params()?; + match params { + crate::params::Params::None => {} + _ => todo!(), + } + #[allow(clippy::arc_with_non_send_sync)] + let rows = Rows { + inner: Arc::clone(&self.inner), + }; + Ok(rows) } pub async fn execute(&mut self, params: impl IntoParams) -> Result { @@ -110,19 +150,44 @@ pub enum Params { pub struct Transaction {} pub struct Rows { - _inner: Rc, + inner: Arc>, } +unsafe impl Send for Rows {} +unsafe impl Sync for Rows {} + impl Rows { pub async fn next(&mut self) -> Result> { - todo!(); + let mut stmt = self + .inner + .lock() + .map_err(|e| Error::MutexError(e.to_string()))?; + + match stmt.step() { + Ok(limbo_core::StepResult::Row) => { + let row = stmt.row().unwrap(); + Ok(Some(Row { + values: row.get_values().to_vec(), + })) + } + _ => Ok(None), + } } } -pub struct Row {} +pub struct Row { + values: Vec, +} + +unsafe impl Send for Row {} +unsafe impl Sync for Row {} impl Row { - pub fn get_value(&self, _index: usize) -> Result { - todo!(); + pub fn get_value(&self, index: usize) -> Result { + let value = &self.values[index]; + match value { + limbo_core::OwnedValue::Integer(i) => Ok(Value::Integer(*i)), + _ => todo!(), + } } }