oxygengine_backend_web/
storage.rs1use core::storage::{StorageEngine, StorageError, StorageResult};
2use std::fmt::Write;
3
4fn window() -> web_sys::Window {
5 web_sys::window().expect("no global `window` exists")
6}
7
8#[derive(Default, Copy, Clone)]
9pub struct WebStorageEngine;
10
11impl StorageEngine for WebStorageEngine {
12 fn load(&mut self, path: &str) -> StorageResult<Vec<u8>> {
13 if let Ok(Some(storage)) = window().local_storage() {
14 if let Ok(Some(data)) = storage.get_item(path) {
15 Self::str_to_bytes(&data)
16 } else {
17 Err(StorageError::CouldNotLoadData(format!(
18 "Could not load data from: {}",
19 path
20 )))
21 }
22 } else {
23 Err(StorageError::CouldNotLoadData(format!(
24 "Could not load data from: {}",
25 path
26 )))
27 }
28 }
29
30 fn store(&mut self, path: &str, data: &[u8]) -> StorageResult<()> {
31 if let Ok(Some(storage)) = window().local_storage() {
32 if storage
33 .set_item(path, &Self::bytes_to_string(data)?)
34 .is_ok()
35 {
36 Ok(())
37 } else {
38 Err(StorageError::CouldNotStoreData(format!(
39 "Could not store data to: {}",
40 path
41 )))
42 }
43 } else {
44 Err(StorageError::CouldNotStoreData(format!(
45 "Could not store data to: {}",
46 path
47 )))
48 }
49 }
50}
51
52impl WebStorageEngine {
53 fn str_to_bytes(data: &str) -> StorageResult<Vec<u8>> {
54 let mut result = Vec::with_capacity(data.len() / 2);
55 for i in 0..data.len() / 2 {
56 let chunk = &data[(i * 2)..(i * 2 + 2)];
57 if let Ok(byte) = u8::from_str_radix(chunk, 16) {
58 result.push(byte);
59 } else {
60 return Err(StorageError::CouldNotStoreData(format!(
61 "Could not convert to byte: {}",
62 chunk
63 )));
64 }
65 }
66 Ok(result)
67 }
68
69 fn bytes_to_string(data: &[u8]) -> StorageResult<String> {
70 let mut result = String::with_capacity(data.len() * 2);
71 for byte in data {
72 if write!(&mut result, "{:02X}", byte).is_err() {
73 return Err(StorageError::CouldNotStoreData(format!(
74 "Could not convert byte: {}",
75 byte
76 )));
77 }
78 }
79 Ok(result)
80 }
81}