- 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.
115 lines
4.0 KiB
Rust
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}")))?
|
|
}
|
|
}
|