1use std::collections::HashMap;
26use std::ops::Range;
27use std::sync::{Arc, RwLock};
28
29use async_trait::async_trait;
30use bytes::Bytes;
31use futures::StreamExt;
32use futures::stream::BoxStream;
33use serde::{Deserialize, Serialize};
34
35use crate::io::{
36 FileMetadata, FileRead, FileWrite, InputFile, OutputFile, Storage, StorageConfig,
37 StorageFactory,
38};
39use crate::{Error, ErrorKind, Result};
40
41#[derive(Debug, Clone, Default, Serialize, Deserialize)]
62pub struct MemoryStorage {
63 #[serde(skip, default = "default_memory_data")]
64 data: Arc<RwLock<HashMap<String, Bytes>>>,
65}
66
67fn default_memory_data() -> Arc<RwLock<HashMap<String, Bytes>>> {
68 Arc::new(RwLock::new(HashMap::new()))
69}
70
71impl MemoryStorage {
72 pub fn new() -> Self {
74 Self {
75 data: Arc::new(RwLock::new(HashMap::new())),
76 }
77 }
78
79 pub(crate) fn normalize_path(path: &str) -> String {
87 let path = path.strip_prefix("memory://").unwrap_or(path);
89 let path = path.strip_prefix("memory:/").unwrap_or(path);
91 path.trim_start_matches('/').to_string()
93 }
94}
95
96#[async_trait]
97#[typetag::serde]
98impl Storage for MemoryStorage {
99 async fn exists(&self, path: &str) -> Result<bool> {
100 let normalized = Self::normalize_path(path);
101 let data = self.data.read().map_err(|e| {
102 Error::new(
103 ErrorKind::Unexpected,
104 format!("Failed to acquire read lock: {e}"),
105 )
106 })?;
107 Ok(data.contains_key(&normalized))
108 }
109
110 async fn metadata(&self, path: &str) -> Result<FileMetadata> {
111 let normalized = Self::normalize_path(path);
112 let data = self.data.read().map_err(|e| {
113 Error::new(
114 ErrorKind::Unexpected,
115 format!("Failed to acquire read lock: {e}"),
116 )
117 })?;
118 match data.get(&normalized) {
119 Some(bytes) => Ok(FileMetadata {
120 size: bytes.len() as u64,
121 }),
122 None => Err(Error::new(
123 ErrorKind::DataInvalid,
124 format!("File not found: {path}"),
125 )),
126 }
127 }
128
129 async fn read(&self, path: &str) -> Result<Bytes> {
130 let normalized = Self::normalize_path(path);
131 let data = self.data.read().map_err(|e| {
132 Error::new(
133 ErrorKind::Unexpected,
134 format!("Failed to acquire read lock: {e}"),
135 )
136 })?;
137 match data.get(&normalized) {
138 Some(bytes) => Ok(bytes.clone()),
139 None => Err(Error::new(
140 ErrorKind::DataInvalid,
141 format!("File not found: {path}"),
142 )),
143 }
144 }
145
146 async fn reader(&self, path: &str) -> Result<Box<dyn FileRead>> {
147 let normalized = Self::normalize_path(path);
148 let data = self.data.read().map_err(|e| {
149 Error::new(
150 ErrorKind::Unexpected,
151 format!("Failed to acquire read lock: {e}"),
152 )
153 })?;
154 match data.get(&normalized) {
155 Some(bytes) => Ok(Box::new(MemoryFileRead::new(bytes.clone()))),
156 None => Err(Error::new(
157 ErrorKind::DataInvalid,
158 format!("File not found: {path}"),
159 )),
160 }
161 }
162
163 async fn write(&self, path: &str, bs: Bytes) -> Result<()> {
164 let normalized = Self::normalize_path(path);
165 let mut data = self.data.write().map_err(|e| {
166 Error::new(
167 ErrorKind::Unexpected,
168 format!("Failed to acquire write lock: {e}"),
169 )
170 })?;
171 data.insert(normalized, bs);
172 Ok(())
173 }
174
175 async fn writer(&self, path: &str) -> Result<Box<dyn FileWrite>> {
176 let normalized = Self::normalize_path(path);
177 Ok(Box::new(MemoryFileWrite::new(
178 self.data.clone(),
179 normalized,
180 )))
181 }
182
183 async fn delete(&self, path: &str) -> Result<()> {
184 let normalized = Self::normalize_path(path);
185 let mut data = self.data.write().map_err(|e| {
186 Error::new(
187 ErrorKind::Unexpected,
188 format!("Failed to acquire write lock: {e}"),
189 )
190 })?;
191 data.remove(&normalized);
192 Ok(())
193 }
194
195 async fn delete_prefix(&self, path: &str) -> Result<()> {
196 let normalized = Self::normalize_path(path);
197 let prefix = if normalized.ends_with('/') {
198 normalized
199 } else {
200 format!("{normalized}/")
201 };
202
203 let mut data = self.data.write().map_err(|e| {
204 Error::new(
205 ErrorKind::Unexpected,
206 format!("Failed to acquire write lock: {e}"),
207 )
208 })?;
209
210 let keys_to_remove: Vec<String> = data
212 .keys()
213 .filter(|k| k.starts_with(&prefix))
214 .cloned()
215 .collect();
216
217 for key in keys_to_remove {
218 data.remove(&key);
219 }
220
221 Ok(())
222 }
223
224 async fn delete_stream(&self, mut paths: BoxStream<'static, String>) -> Result<()> {
225 while let Some(path) = paths.next().await {
226 self.delete(&path).await?;
227 }
228 Ok(())
229 }
230
231 fn new_input(&self, path: &str) -> Result<InputFile> {
232 Ok(InputFile::new(Arc::new(self.clone()), path.to_string()))
233 }
234
235 fn new_output(&self, path: &str) -> Result<OutputFile> {
236 Ok(OutputFile::new(Arc::new(self.clone()), path.to_string()))
237 }
238}
239
240#[derive(Clone, Debug, Default, Serialize, Deserialize)]
246pub struct MemoryStorageFactory;
247
248#[typetag::serde]
249impl StorageFactory for MemoryStorageFactory {
250 fn build(&self, _config: &StorageConfig) -> Result<Arc<dyn Storage>> {
251 Ok(Arc::new(MemoryStorage::new()))
252 }
253}
254
255#[derive(Debug)]
257pub struct MemoryFileRead {
258 data: Bytes,
259}
260
261impl MemoryFileRead {
262 pub fn new(data: Bytes) -> Self {
264 Self { data }
265 }
266}
267
268#[async_trait]
269impl FileRead for MemoryFileRead {
270 async fn read(&self, range: Range<u64>) -> Result<Bytes> {
271 let start = range.start as usize;
272 let end = range.end as usize;
273
274 if start > self.data.len() || end > self.data.len() {
275 return Err(Error::new(
276 ErrorKind::DataInvalid,
277 format!(
278 "Range {}..{} is out of bounds for data of length {}",
279 start,
280 end,
281 self.data.len()
282 ),
283 ));
284 }
285
286 Ok(self.data.slice(start..end))
287 }
288}
289
290#[derive(Debug)]
296pub struct MemoryFileWrite {
297 data: Arc<RwLock<HashMap<String, Bytes>>>,
298 path: String,
299 buffer: Vec<u8>,
300 closed: bool,
301}
302
303impl MemoryFileWrite {
304 pub fn new(data: Arc<RwLock<HashMap<String, Bytes>>>, path: String) -> Self {
306 Self {
307 data,
308 path,
309 buffer: Vec::new(),
310 closed: false,
311 }
312 }
313}
314
315#[async_trait]
316impl FileWrite for MemoryFileWrite {
317 async fn write(&mut self, bs: Bytes) -> Result<()> {
318 if self.closed {
319 return Err(Error::new(
320 ErrorKind::DataInvalid,
321 "Cannot write to closed file",
322 ));
323 }
324 self.buffer.extend_from_slice(&bs);
325 Ok(())
326 }
327
328 async fn close(&mut self) -> Result<()> {
329 if self.closed {
330 return Err(Error::new(ErrorKind::DataInvalid, "File already closed"));
331 }
332
333 let mut data = self.data.write().map_err(|e| {
334 Error::new(
335 ErrorKind::Unexpected,
336 format!("Failed to acquire write lock: {e}"),
337 )
338 })?;
339
340 data.insert(
341 self.path.clone(),
342 Bytes::from(std::mem::take(&mut self.buffer)),
343 );
344 self.closed = true;
345 Ok(())
346 }
347}
348
349#[cfg(test)]
350mod tests {
351 use super::*;
352
353 #[test]
354 fn test_normalize_path() {
355 assert_eq!(
357 MemoryStorage::normalize_path("memory://path/to/file"),
358 "path/to/file"
359 );
360
361 assert_eq!(
363 MemoryStorage::normalize_path("memory:/path/to/file"),
364 "path/to/file"
365 );
366
367 assert_eq!(
369 MemoryStorage::normalize_path("/path/to/file"),
370 "path/to/file"
371 );
372
373 assert_eq!(
375 MemoryStorage::normalize_path("path/to/file"),
376 "path/to/file"
377 );
378
379 assert_eq!(
381 MemoryStorage::normalize_path("///path/to/file"),
382 "path/to/file"
383 );
384
385 assert_eq!(
387 MemoryStorage::normalize_path("memory:///path/to/file"),
388 "path/to/file"
389 );
390 }
391
392 #[tokio::test]
393 async fn test_memory_storage_write_read() {
394 let storage = MemoryStorage::new();
395 let path = "memory://test/file.txt";
396 let content = Bytes::from("Hello, World!");
397
398 storage.write(path, content.clone()).await.unwrap();
400
401 let read_content = storage.read(path).await.unwrap();
403 assert_eq!(read_content, content);
404 }
405
406 #[tokio::test]
407 async fn test_memory_storage_exists() {
408 let storage = MemoryStorage::new();
409 let path = "memory://test/file.txt";
410
411 assert!(!storage.exists(path).await.unwrap());
413
414 storage.write(path, Bytes::from("test")).await.unwrap();
416
417 assert!(storage.exists(path).await.unwrap());
419 }
420
421 #[tokio::test]
422 async fn test_memory_storage_metadata() {
423 let storage = MemoryStorage::new();
424 let path = "memory://test/file.txt";
425 let content = Bytes::from("Hello, World!");
426
427 storage.write(path, content.clone()).await.unwrap();
428
429 let metadata = storage.metadata(path).await.unwrap();
430 assert_eq!(metadata.size, content.len() as u64);
431 }
432
433 #[tokio::test]
434 async fn test_memory_storage_delete() {
435 let storage = MemoryStorage::new();
436 let path = "memory://test/file.txt";
437
438 storage.write(path, Bytes::from("test")).await.unwrap();
439 assert!(storage.exists(path).await.unwrap());
440
441 storage.delete(path).await.unwrap();
442 assert!(!storage.exists(path).await.unwrap());
443 }
444
445 #[tokio::test]
446 async fn test_memory_storage_delete_prefix() {
447 let storage = MemoryStorage::new();
448
449 storage
451 .write("memory://dir/file1.txt", Bytes::from("1"))
452 .await
453 .unwrap();
454 storage
455 .write("memory://dir/file2.txt", Bytes::from("2"))
456 .await
457 .unwrap();
458 storage
459 .write("memory://other/file.txt", Bytes::from("3"))
460 .await
461 .unwrap();
462
463 storage.delete_prefix("memory://dir").await.unwrap();
465
466 assert!(!storage.exists("memory://dir/file1.txt").await.unwrap());
468 assert!(!storage.exists("memory://dir/file2.txt").await.unwrap());
469
470 assert!(storage.exists("memory://other/file.txt").await.unwrap());
472 }
473
474 #[tokio::test]
475 async fn test_memory_storage_reader() {
476 let storage = MemoryStorage::new();
477 let path = "memory://test/file.txt";
478 let content = Bytes::from("Hello, World!");
479
480 storage.write(path, content.clone()).await.unwrap();
481
482 let reader = storage.reader(path).await.unwrap();
483 let read_content = reader.read(0..content.len() as u64).await.unwrap();
484 assert_eq!(read_content, content);
485
486 let partial = reader.read(0..5).await.unwrap();
488 assert_eq!(partial, Bytes::from("Hello"));
489 }
490
491 #[tokio::test]
492 async fn test_memory_storage_writer() {
493 let storage = MemoryStorage::new();
494 let path = "memory://test/file.txt";
495
496 let mut writer = storage.writer(path).await.unwrap();
497 writer.write(Bytes::from("Hello, ")).await.unwrap();
498 writer.write(Bytes::from("World!")).await.unwrap();
499 writer.close().await.unwrap();
500
501 let content = storage.read(path).await.unwrap();
502 assert_eq!(content, Bytes::from("Hello, World!"));
503 }
504
505 #[tokio::test]
506 async fn test_memory_file_write_double_close() {
507 let storage = MemoryStorage::new();
508 let path = "memory://test/file.txt";
509
510 let mut writer = storage.writer(path).await.unwrap();
511 writer.write(Bytes::from("test")).await.unwrap();
512 writer.close().await.unwrap();
513
514 let result = writer.close().await;
516 assert!(result.is_err());
517 }
518
519 #[tokio::test]
520 async fn test_memory_file_write_after_close() {
521 let storage = MemoryStorage::new();
522 let path = "memory://test/file.txt";
523
524 let mut writer = storage.writer(path).await.unwrap();
525 writer.close().await.unwrap();
526
527 let result = writer.write(Bytes::from("test")).await;
529 assert!(result.is_err());
530 }
531
532 #[tokio::test]
533 async fn test_memory_file_read_out_of_bounds() {
534 let storage = MemoryStorage::new();
535 let path = "memory://test/file.txt";
536 let content = Bytes::from("Hello");
537
538 storage.write(path, content).await.unwrap();
539
540 let reader = storage.reader(path).await.unwrap();
541 let result = reader.read(0..100).await;
542 assert!(result.is_err());
543 }
544
545 #[test]
546 fn test_memory_storage_serialization() {
547 let storage = MemoryStorage::new();
548
549 let serialized = serde_json::to_string(&storage).unwrap();
551
552 let deserialized: MemoryStorage = serde_json::from_str(&serialized).unwrap();
554
555 assert!(deserialized.data.read().unwrap().is_empty());
557 }
558
559 #[test]
560 fn test_memory_storage_factory() {
561 let factory = MemoryStorageFactory;
562 let config = StorageConfig::new();
563 let storage = factory.build(&config).unwrap();
564
565 assert!(format!("{storage:?}").contains("MemoryStorage"));
567 }
568
569 #[test]
570 fn test_memory_storage_factory_serialization() {
571 let factory = MemoryStorageFactory;
572
573 let serialized = serde_json::to_string(&factory).unwrap();
575
576 let deserialized: MemoryStorageFactory = serde_json::from_str(&serialized).unwrap();
578
579 let config = StorageConfig::new();
581 let storage = deserialized.build(&config).unwrap();
582 assert!(format!("{storage:?}").contains("MemoryStorage"));
583 }
584
585 #[tokio::test]
586 async fn test_path_normalization_consistency() {
587 let storage = MemoryStorage::new();
588 let content = Bytes::from("test content");
589
590 storage
592 .write("memory://path/to/file", content.clone())
593 .await
594 .unwrap();
595
596 assert_eq!(
598 storage.read("memory://path/to/file").await.unwrap(),
599 content
600 );
601 assert_eq!(storage.read("memory:/path/to/file").await.unwrap(), content);
602 assert_eq!(storage.read("/path/to/file").await.unwrap(), content);
603 assert_eq!(storage.read("path/to/file").await.unwrap(), content);
604 }
605
606 #[tokio::test]
607 async fn test_memory_storage_delete_stream() {
608 use futures::stream;
609
610 let storage = MemoryStorage::new();
611
612 storage
614 .write("memory://file1.txt", Bytes::from("1"))
615 .await
616 .unwrap();
617 storage
618 .write("memory://file2.txt", Bytes::from("2"))
619 .await
620 .unwrap();
621 storage
622 .write("memory://file3.txt", Bytes::from("3"))
623 .await
624 .unwrap();
625
626 assert!(storage.exists("memory://file1.txt").await.unwrap());
628 assert!(storage.exists("memory://file2.txt").await.unwrap());
629 assert!(storage.exists("memory://file3.txt").await.unwrap());
630
631 let paths = vec![
633 "memory://file1.txt".to_string(),
634 "memory://file2.txt".to_string(),
635 ];
636 let path_stream = stream::iter(paths).boxed();
637 storage.delete_stream(path_stream).await.unwrap();
638
639 assert!(!storage.exists("memory://file1.txt").await.unwrap());
641 assert!(!storage.exists("memory://file2.txt").await.unwrap());
642
643 assert!(storage.exists("memory://file3.txt").await.unwrap());
645 }
646
647 #[tokio::test]
648 async fn test_memory_storage_delete_stream_empty() {
649 use futures::stream;
650
651 let storage = MemoryStorage::new();
652
653 let path_stream = stream::iter(Vec::<String>::new()).boxed();
655 storage.delete_stream(path_stream).await.unwrap();
656 }
657}