1use crate::traits::BlockStore;
7use async_trait::async_trait;
8use dashmap::DashMap;
9use ipfrs_core::{Block, Cid, Result};
10use std::sync::Arc;
11
12#[derive(Clone)]
14pub struct MemoryBlockStore {
15 blocks: Arc<DashMap<Cid, Block>>,
16}
17
18impl MemoryBlockStore {
19 pub fn new() -> Self {
21 Self {
22 blocks: Arc::new(DashMap::new()),
23 }
24 }
25
26 pub fn clear(&self) {
28 self.blocks.clear();
29 }
30}
31
32impl Default for MemoryBlockStore {
33 fn default() -> Self {
34 Self::new()
35 }
36}
37
38#[async_trait]
39impl BlockStore for MemoryBlockStore {
40 async fn put(&self, block: &Block) -> Result<()> {
41 self.blocks.insert(*block.cid(), block.clone());
42 Ok(())
43 }
44
45 async fn get(&self, cid: &Cid) -> Result<Option<Block>> {
46 Ok(self.blocks.get(cid).map(|entry| entry.value().clone()))
47 }
48
49 async fn has(&self, cid: &Cid) -> Result<bool> {
50 Ok(self.blocks.contains_key(cid))
51 }
52
53 async fn delete(&self, cid: &Cid) -> Result<()> {
54 self.blocks.remove(cid);
55 Ok(())
56 }
57
58 fn list_cids(&self) -> Result<Vec<Cid>> {
59 Ok(self.blocks.iter().map(|entry| *entry.key()).collect())
60 }
61
62 fn len(&self) -> usize {
63 self.blocks.len()
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70 use bytes::Bytes;
71
72 #[tokio::test]
73 async fn test_put_get() {
74 let store = MemoryBlockStore::new();
75 let data = Bytes::from("hello");
76 let block = Block::new(data.clone()).unwrap();
77
78 store.put(&block).await.unwrap();
79 let retrieved = store.get(block.cid()).await.unwrap();
80 assert!(retrieved.is_some());
81 assert_eq!(retrieved.unwrap().data(), &data);
82 }
83
84 #[tokio::test]
85 async fn test_has() {
86 let store = MemoryBlockStore::new();
87 let data = Bytes::from("hello");
88 let block = Block::new(data).unwrap();
89
90 assert!(!store.has(block.cid()).await.unwrap());
91 store.put(&block).await.unwrap();
92 assert!(store.has(block.cid()).await.unwrap());
93 }
94
95 #[tokio::test]
96 async fn test_delete() {
97 let store = MemoryBlockStore::new();
98 let data = Bytes::from("hello");
99 let block = Block::new(data).unwrap();
100
101 store.put(&block).await.unwrap();
102 assert!(store.has(block.cid()).await.unwrap());
103
104 store.delete(block.cid()).await.unwrap();
105 assert!(!store.has(block.cid()).await.unwrap());
106 }
107
108 #[tokio::test]
109 async fn test_batch_operations() {
110 let store = MemoryBlockStore::new();
111 let block1 = Block::new(Bytes::from("hello")).unwrap();
112 let block2 = Block::new(Bytes::from("world")).unwrap();
113
114 let blocks = vec![block1.clone(), block2.clone()];
115 store.put_many(&blocks).await.unwrap();
116
117 let results = store
118 .get_many(&[*block1.cid(), *block2.cid()])
119 .await
120 .unwrap();
121 assert_eq!(results.len(), 2);
122 assert!(results[0].is_some());
123 assert!(results[1].is_some());
124 }
125
126 #[tokio::test]
127 async fn test_len() {
128 let store = MemoryBlockStore::new();
129 assert_eq!(store.len(), 0);
130
131 let block = Block::new(Bytes::from("test")).unwrap();
132 store.put(&block).await.unwrap();
133 assert_eq!(store.len(), 1);
134 }
135
136 #[tokio::test]
137 async fn test_list_cids() {
138 let store = MemoryBlockStore::new();
139 let block1 = Block::new(Bytes::from("hello")).unwrap();
140 let block2 = Block::new(Bytes::from("world")).unwrap();
141
142 store.put(&block1).await.unwrap();
143 store.put(&block2).await.unwrap();
144
145 let cids = store.list_cids().unwrap();
146 assert_eq!(cids.len(), 2);
147 assert!(cids.contains(block1.cid()));
148 assert!(cids.contains(block2.cid()));
149 }
150}