oxihuman_core/
object_storage_stub.rs1#![allow(dead_code)]
4
5use std::collections::HashMap;
8
9#[derive(Debug, Clone)]
11pub struct ObjectMeta {
12 pub key: String,
13 pub size_bytes: u64,
14 pub etag: String,
15 pub content_type: String,
16}
17
18impl ObjectMeta {
19 pub fn new(key: &str, size_bytes: u64) -> Self {
20 ObjectMeta {
21 key: key.to_string(),
22 size_bytes,
23 etag: format!("{:x}", size_bytes ^ 0xDEAD_BEEF),
24 content_type: "application/octet-stream".to_string(),
25 }
26 }
27}
28
29#[derive(Debug, Clone)]
31pub struct StoredObject {
32 pub meta: ObjectMeta,
33 pub data: Vec<u8>,
34}
35
36impl StoredObject {
37 pub fn new(key: &str, data: Vec<u8>) -> Self {
38 let size = data.len() as u64;
39 StoredObject {
40 meta: ObjectMeta::new(key, size),
41 data,
42 }
43 }
44}
45
46pub struct ObjectStorage {
48 bucket: String,
49 objects: HashMap<String, StoredObject>,
50}
51
52impl ObjectStorage {
53 pub fn new(bucket: &str) -> Self {
54 ObjectStorage {
55 bucket: bucket.to_string(),
56 objects: HashMap::new(),
57 }
58 }
59
60 pub fn put(&mut self, key: &str, data: Vec<u8>) {
61 self.objects
62 .insert(key.to_string(), StoredObject::new(key, data));
63 }
64
65 pub fn get(&self, key: &str) -> Option<&StoredObject> {
66 self.objects.get(key)
67 }
68
69 pub fn delete(&mut self, key: &str) -> bool {
70 self.objects.remove(key).is_some()
71 }
72
73 pub fn list(&self, prefix: &str) -> Vec<&ObjectMeta> {
74 self.objects
75 .values()
76 .filter(|o| o.meta.key.starts_with(prefix))
77 .map(|o| &o.meta)
78 .collect()
79 }
80
81 pub fn exists(&self, key: &str) -> bool {
82 self.objects.contains_key(key)
83 }
84
85 pub fn object_count(&self) -> usize {
86 self.objects.len()
87 }
88
89 pub fn total_size(&self) -> u64 {
90 self.objects.values().map(|o| o.meta.size_bytes).sum()
91 }
92
93 pub fn bucket(&self) -> &str {
94 &self.bucket
95 }
96}
97
98impl Default for ObjectStorage {
99 fn default() -> Self {
100 Self::new("default-bucket")
101 }
102}
103
104pub fn new_object_storage(bucket: &str) -> ObjectStorage {
106 ObjectStorage::new(bucket)
107}
108
109pub fn upload(storage: &mut ObjectStorage, key: &str, data: &[u8]) -> String {
111 storage.put(key, data.to_vec());
112 key.to_string()
113}
114
115pub fn download(storage: &ObjectStorage, key: &str) -> Option<Vec<u8>> {
117 storage.get(key).map(|o| o.data.clone())
118}
119
120pub fn copy_object(storage: &mut ObjectStorage, src_key: &str, dst_key: &str) -> bool {
122 if let Some(obj) = storage.get(src_key).cloned() {
123 storage.put(dst_key, obj.data);
124 true
125 } else {
126 false
127 }
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133
134 #[test]
135 fn test_put_and_get() {
136 let mut s = new_object_storage("bucket");
137 s.put("key1", b"hello".to_vec());
138 assert!(s.get("key1").is_some());
139 }
140
141 #[test]
142 fn test_get_missing() {
143 let s = new_object_storage("bucket");
144 assert!(s.get("nonexistent").is_none());
145 }
146
147 #[test]
148 fn test_delete() {
149 let mut s = new_object_storage("bucket");
150 s.put("k", b"data".to_vec());
151 assert!(s.delete("k"));
152 assert!(!s.exists("k"));
153 }
154
155 #[test]
156 fn test_list_prefix() {
157 let mut s = new_object_storage("bucket");
158 s.put("images/a.png", b"img".to_vec());
159 s.put("docs/b.txt", b"doc".to_vec());
160 let imgs = s.list("images/");
161 assert_eq!(imgs.len(), 1);
162 }
163
164 #[test]
165 fn test_total_size() {
166 let mut s = new_object_storage("bucket");
167 s.put("a", vec![0u8; 100]);
168 s.put("b", vec![0u8; 200]);
169 assert_eq!(s.total_size(), 300);
170 }
171
172 #[test]
173 fn test_upload_download() {
174 let mut s = new_object_storage("bucket");
175 upload(&mut s, "file.bin", &[1, 2, 3]);
176 let data = download(&s, "file.bin").expect("should succeed");
177 assert_eq!(data, vec![1, 2, 3]);
178 }
179
180 #[test]
181 fn test_copy_object() {
182 let mut s = new_object_storage("bucket");
183 s.put("src", b"payload".to_vec());
184 assert!(copy_object(&mut s, "src", "dst"));
185 assert!(s.exists("dst"));
186 }
187
188 #[test]
189 fn test_copy_missing_returns_false() {
190 let mut s = new_object_storage("bucket");
191 assert!(!copy_object(&mut s, "missing", "dst"));
192 }
193
194 #[test]
195 fn test_object_count() {
196 let mut s = new_object_storage("bucket");
197 s.put("x", vec![]);
198 s.put("y", vec![]);
199 assert_eq!(s.object_count(), 2);
200 }
201
202 #[test]
203 fn test_bucket_name() {
204 let s = ObjectStorage::new("my-bucket");
205 assert_eq!(s.bucket(), "my-bucket");
206 }
207}