#[cfg(target_arch = "wasm32")]
use std::collections::HashMap;
#[cfg(target_arch = "wasm32")]
use std::sync::{Arc, RwLock};
#[cfg(target_arch = "wasm32")]
use crate::error_chirho::{ErrorChirho, ResultChirho};
#[cfg(target_arch = "wasm32")]
use super::backend_chirho::StorageBackendChirho;
#[cfg(target_arch = "wasm32")]
pub struct WasmBackendChirho {
virtual_fs_chirho: Arc<RwLock<HashMap<String, Vec<u8>>>>,
virtual_dirs_chirho: Arc<RwLock<HashMap<String, Vec<String>>>>,
}
#[cfg(target_arch = "wasm32")]
impl WasmBackendChirho {
pub fn new_chirho() -> Self {
Self {
virtual_fs_chirho: Arc::new(RwLock::new(HashMap::new())),
virtual_dirs_chirho: Arc::new(RwLock::new(HashMap::new())),
}
}
pub fn preload_file_chirho(&self, path_chirho: &str, data_chirho: &[u8]) {
if let Ok(mut fs_chirho) = self.virtual_fs_chirho.write() {
fs_chirho.insert(path_chirho.to_string(), data_chirho.to_vec());
}
if let Some(parent_chirho) = Self::parent_path_chirho(path_chirho) {
if let Some(name_chirho) = Self::file_name_chirho(path_chirho) {
if let Ok(mut dirs_chirho) = self.virtual_dirs_chirho.write() {
dirs_chirho
.entry(parent_chirho.to_string())
.or_default()
.push(name_chirho.to_string());
}
}
}
}
pub fn clear_chirho(&self) {
if let Ok(mut fs_chirho) = self.virtual_fs_chirho.write() {
fs_chirho.clear();
}
if let Ok(mut dirs_chirho) = self.virtual_dirs_chirho.write() {
dirs_chirho.clear();
}
}
fn parent_path_chirho(path_chirho: &str) -> Option<&str> {
path_chirho.rfind('/').map(|idx_chirho| &path_chirho[..idx_chirho])
}
fn file_name_chirho(path_chirho: &str) -> Option<&str> {
path_chirho.rfind('/').map(|idx_chirho| &path_chirho[idx_chirho + 1..])
}
}
#[cfg(target_arch = "wasm32")]
impl StorageBackendChirho for WasmBackendChirho {
fn read_file_chirho(&self, path_chirho: &str) -> ResultChirho<Vec<u8>> {
let fs_chirho = self.virtual_fs_chirho.read().map_err(|_| {
ErrorChirho::generic_chirho("Failed to acquire read lock".to_string())
})?;
fs_chirho
.get(path_chirho)
.cloned()
.ok_or_else(|| ErrorChirho::generic_chirho(format!("File not found: {}", path_chirho)))
}
fn read_range_chirho(
&self,
path_chirho: &str,
offset_chirho: u64,
len_chirho: usize,
) -> ResultChirho<Vec<u8>> {
let data_chirho = self.read_file_chirho(path_chirho)?;
let start_chirho = offset_chirho as usize;
let end_chirho = (start_chirho + len_chirho).min(data_chirho.len());
if start_chirho >= data_chirho.len() {
return Err(ErrorChirho::generic_chirho(format!(
"Offset {} beyond file size {}",
offset_chirho,
data_chirho.len()
)));
}
Ok(data_chirho[start_chirho..end_chirho].to_vec())
}
fn write_file_chirho(&self, path_chirho: &str, data_chirho: &[u8]) -> ResultChirho<()> {
self.preload_file_chirho(path_chirho, data_chirho);
Ok(())
}
fn file_exists_chirho(&self, path_chirho: &str) -> bool {
if let Ok(fs_chirho) = self.virtual_fs_chirho.read() {
fs_chirho.contains_key(path_chirho)
} else {
false
}
}
fn list_dir_chirho(&self, path_chirho: &str) -> ResultChirho<Vec<String>> {
let dirs_chirho = self.virtual_dirs_chirho.read().map_err(|_| {
ErrorChirho::generic_chirho("Failed to acquire read lock".to_string())
})?;
Ok(dirs_chirho.get(path_chirho).cloned().unwrap_or_default())
}
fn create_dir_chirho(&self, path_chirho: &str) -> ResultChirho<()> {
let mut dirs_chirho = self.virtual_dirs_chirho.write().map_err(|_| {
ErrorChirho::generic_chirho("Failed to acquire write lock".to_string())
})?;
dirs_chirho.entry(path_chirho.to_string()).or_default();
Ok(())
}
fn file_size_chirho(&self, path_chirho: &str) -> ResultChirho<u64> {
let fs_chirho = self.virtual_fs_chirho.read().map_err(|_| {
ErrorChirho::generic_chirho("Failed to acquire read lock".to_string())
})?;
fs_chirho
.get(path_chirho)
.map(|d_chirho| d_chirho.len() as u64)
.ok_or_else(|| ErrorChirho::generic_chirho(format!("File not found: {}", path_chirho)))
}
fn append_file_chirho(&self, path_chirho: &str, data_chirho: &[u8]) -> ResultChirho<()> {
let mut fs_chirho = self.virtual_fs_chirho.write().map_err(|_| {
ErrorChirho::generic_chirho("Failed to acquire write lock".to_string())
})?;
let entry_chirho = fs_chirho.entry(path_chirho.to_string()).or_default();
entry_chirho.extend_from_slice(data_chirho);
Ok(())
}
}
#[cfg(target_arch = "wasm32")]
unsafe impl Send for WasmBackendChirho {}
#[cfg(target_arch = "wasm32")]
unsafe impl Sync for WasmBackendChirho {}
#[cfg(all(test, target_arch = "wasm32"))]
mod tests_chirho {
use super::*;
#[test]
fn test_preload_and_read_chirho() {
let backend_chirho = WasmBackendChirho::new_chirho();
backend_chirho.preload_file_chirho("modules/kjv/nt", b"test data");
let data_chirho = backend_chirho.read_file_chirho("modules/kjv/nt").unwrap();
assert_eq!(&data_chirho, b"test data");
}
#[test]
fn test_read_range_wasm_chirho() {
let backend_chirho = WasmBackendChirho::new_chirho();
backend_chirho.preload_file_chirho("test.txt", b"Hello, World!");
let data_chirho = backend_chirho.read_range_chirho("test.txt", 7, 5).unwrap();
assert_eq!(&data_chirho, b"World");
}
#[test]
fn test_file_not_found_chirho() {
let backend_chirho = WasmBackendChirho::new_chirho();
let result_chirho = backend_chirho.read_file_chirho("nonexistent");
assert!(result_chirho.is_err());
}
#[test]
fn test_directory_listing_chirho() {
let backend_chirho = WasmBackendChirho::new_chirho();
backend_chirho.preload_file_chirho("modules/kjv/nt", b"nt");
backend_chirho.preload_file_chirho("modules/kjv/ot", b"ot");
let files_chirho = backend_chirho.list_dir_chirho("modules/kjv").unwrap();
assert!(files_chirho.contains(&"nt".to_string()));
assert!(files_chirho.contains(&"ot".to_string()));
}
}