sal-modular/kvstore/src/native.rs
Sameh Abouelsaad cea2d7e655 feat: Refactor kvstore and vault to use features and logging
- Remove hardcoded dependencies in kvstore Cargo.toml; use features
  instead. This allows for more flexible compilation for different
  targets (native vs. WASM).
- Improve logging in vault crate using the `log` crate. This makes
  debugging easier and provides more informative output during
  execution.  Native tests use `env_logger`, WASM tests use
  `console_log`.
- Update README to reflect new logging best practices.
- Add cfg attributes to native and wasm modules to improve clarity.
- Update traits.rs to specify Send + Sync behavior expectations.
2025-05-15 16:42:19 +03:00

115 lines
4.0 KiB
Rust

//! 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<Db>,
}
impl NativeStore {
pub fn open(path: &str) -> Result<Self> {
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<Option<Vec<u8>>> {
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<bool> {
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<Vec<String>> {
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}")))?
}
}