The saikuro-storage crate provides a unified storage abstraction that works across native and WASM environments. All backends share the same traits, so switching between them is a configuration change.

Storage Traits

KeyValueBackend

The core key-value interface with namespace support:

#[async_trait]
pub trait KeyValueBackend {
    async fn exists(&self, namespace: &str, key: &str) -> Result<bool>;
    async fn get(&self, namespace: &str, key: &str) -> Result<Option<Bytes>>;
    async fn put(&self, namespace: &str, key: &str, value: Bytes) -> Result<()>;
    async fn delete(&self, namespace: &str, key: &str) -> Result<()>;
    async fn list_keys(&self, namespace: &str) -> Result<Vec<String>>;
    async fn list_namespaces(&self) -> Result<Vec<String>>;
    async fn create_namespace(&self, namespace: &str) -> Result<()>;
    async fn delete_namespace(&self, namespace: &str) -> Result<()>;
    async fn clear_namespace(&self, namespace: &str) -> Result<()>;
}

FileBackend

Hierarchical file-like operations:

#[async_trait]
pub trait FileBackend {
    async fn read_file(&self, path: &str) -> Result<Bytes>;
    async fn write_file(&self, path: &str, content: Bytes) -> Result<()>;
    async fn append_file(&self, path: &str, content: Bytes) -> Result<()>;
    async fn delete_file(&self, path: &str) -> Result<()>;
    async fn file_exists(&self, path: &str) -> Result<bool>;
    async fn list_dir(&self, path: &str) -> Result<Vec<String>>;
    async fn create_dir(&self, path: &str) -> Result<()>;
    async fn delete_dir(&self, path: &str) -> Result<()>;
}

KeyValueBackendExt

Extension methods for JSON and MessagePack serialization:

use saikuro_storage::KeyValueBackendExt;

// Automatic JSON round-trip
let user: Option<User> = storage.get_json("users", "alice").await?;
storage.put_json("users", "alice", &user).await?;

// Automatic MessagePack round-trip
let user: Option<User> = storage.get_msgpack("users", "alice").await?;
storage.put_msgpack("users", "alice", &user).await?;

Available Backends

Backend Feature Flag Class Platform
InMemory inmemory InMemoryStorage All
Filesystem fs-storage FilesystemStorage Native
SQLite sqlite-storage SqliteStorage Native
Sled sled-storage SledStorage Native
IndexedDB wasm-storage IndexedDbStorage WASM (browser)
OPFS wasm-storage OpfsStorage WASM (browser)
LocalStorage local-storage LocalStorage WASM (browser)
SessionStorage session-storage SessionStorage WASM (browser)
FsAccess wasm-storage FsAccessStorage WASM (browser)

Usage

use saikuro_storage::{InMemoryStorage, KeyValueBackend, KeyValueBackendExt};
use saikuro_storage::config::StorageConfig;

let storage = InMemoryStorage::with_config(StorageConfig::default());

// Write
storage.put("myapp", "config", b"value".into()).await?;

// Read
let val = storage.get("myapp", "config").await?;

// JSON
storage.put_json("myapp", "settings", &Settings { theme: "dark" }).await?;
let settings: Option<Settings> = storage.get_json("myapp", "settings").await?;

Configuration

use saikuro_storage::config::{StorageConfig, BackendKind, PersistenceMode, CleanupPolicy};

let config = StorageConfig::default()
    .with_namespace_prefix("myapp")
    .with_persistence(PersistenceMode::Persistent)
    .with_cleanup(CleanupPolicy::Ttl(std::time::Duration::from_secs(3600)));

Next Steps