//! Native backend for kvstore using sled //! //! # Runtime Requirement //! #![cfg(not(target_arch = "wasm32"))] //! **A Tokio runtime must be running to use this backend.** //! This library does not start or manage a runtime; it assumes that all async methods are called from within an existing Tokio runtime context (e.g., via `#[tokio::main]` or `tokio::test`). //! //! All blocking I/O is offloaded using `tokio::task::spawn_blocking`. //! //! # Example //! //! Native backend for kvstore using sled //! Only compiled for non-wasm32 targets #[cfg(not(target_arch = "wasm32"))] use crate::traits::KVStore; #[cfg(not(target_arch = "wasm32"))] use crate::error::{KVError, Result}; #[cfg(not(target_arch = "wasm32"))] use async_trait::async_trait; #[cfg(not(target_arch = "wasm32"))] use sled::Db; #[cfg(not(target_arch = "wasm32"))] use std::sync::Arc; #[derive(Clone)] pub struct NativeStore { db: Arc, } impl NativeStore { pub fn open(path: &str) -> Result { let db = sled::open(path).map_err(|e| KVError::Io(std::io::Error::new(std::io::ErrorKind::Other, e)))?; Ok(Self { db: Arc::new(db) }) } } #[async_trait] #[async_trait] impl KVStore for NativeStore { async fn get(&self, key: &str) -> Result>> { let db = self.db.clone(); let key = key.to_owned(); tokio::task::spawn_blocking(move || { db.get(&key) .map_err(|e| KVError::Io(std::io::Error::new(std::io::ErrorKind::Other, e))) .map(|opt| opt.map(|ivec| ivec.to_vec())) }) .await .map_err(|e| KVError::Other(format!("Join error: {e}")))? } async fn set(&self, key: &str, value: &[u8]) -> Result<()> { let db = self.db.clone(); let key = key.to_owned(); let value = value.to_vec(); tokio::task::spawn_blocking(move || { db.insert(&key, value) .map_err(|e| KVError::Io(std::io::Error::new(std::io::ErrorKind::Other, e)))?; db.flush().map_err(|e| KVError::Io(std::io::Error::new(std::io::ErrorKind::Other, e)))?; Ok(()) }) .await .map_err(|e| KVError::Other(format!("Join error: {e}")))? } async fn remove(&self, key: &str) -> Result<()> { let db = self.db.clone(); let key = key.to_owned(); tokio::task::spawn_blocking(move || { db.remove(&key) .map_err(|e| KVError::Io(std::io::Error::new(std::io::ErrorKind::Other, e)))?; db.flush().map_err(|e| KVError::Io(std::io::Error::new(std::io::ErrorKind::Other, e)))?; Ok(()) }) .await .map_err(|e| KVError::Other(format!("Join error: {e}")))? } async fn contains_key(&self, key: &str) -> Result { let db = self.db.clone(); let key = key.to_owned(); tokio::task::spawn_blocking(move || { Ok(db.contains_key(&key) .map_err(|e| KVError::Io(std::io::Error::new(std::io::ErrorKind::Other, e)))?) }) .await .map_err(|e| KVError::Other(format!("Join error: {e}")))? } async fn keys(&self) -> Result> { let db = self.db.clone(); tokio::task::spawn_blocking(move || { let mut keys = Vec::new(); for result in db.iter() { let (key, _) = result.map_err(|e| KVError::Io(std::io::Error::new(std::io::ErrorKind::Other, e)))?; keys.push(String::from_utf8_lossy(&key).to_string()); } Ok(keys) }) .await .map_err(|e| KVError::Other(format!("Join error: {e}")))? } async fn clear(&self) -> Result<()> { let db = self.db.clone(); tokio::task::spawn_blocking(move || { db.clear().map_err(|e| KVError::Io(std::io::Error::new(std::io::ErrorKind::Other, e)))?; db.flush().map_err(|e| KVError::Io(std::io::Error::new(std::io::ErrorKind::Other, e)))?; Ok(()) }) .await .map_err(|e| KVError::Other(format!("Join error: {e}")))? } }