1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
use core::storage::{StorageEngine, StorageError, StorageResult};
use std::fmt::Write;

fn window() -> web_sys::Window {
    web_sys::window().expect("no global `window` exists")
}

#[derive(Default, Copy, Clone)]
pub struct WebStorageEngine;

impl StorageEngine for WebStorageEngine {
    fn load(&mut self, path: &str) -> StorageResult<Vec<u8>> {
        if let Ok(Some(storage)) = window().local_storage() {
            if let Ok(Some(data)) = storage.get_item(path) {
                Self::str_to_bytes(&data)
            } else {
                Err(StorageError::CouldNotLoadData(format!(
                    "Could not load data from: {}",
                    path
                )))
            }
        } else {
            Err(StorageError::CouldNotLoadData(format!(
                "Could not load data from: {}",
                path
            )))
        }
    }

    fn store(&mut self, path: &str, data: &[u8]) -> StorageResult<()> {
        if let Ok(Some(storage)) = window().local_storage() {
            if storage
                .set_item(path, &Self::bytes_to_string(data)?)
                .is_ok()
            {
                Ok(())
            } else {
                Err(StorageError::CouldNotStoreData(format!(
                    "Could not store data to: {}",
                    path
                )))
            }
        } else {
            Err(StorageError::CouldNotStoreData(format!(
                "Could not store data to: {}",
                path
            )))
        }
    }
}

impl WebStorageEngine {
    fn str_to_bytes(data: &str) -> StorageResult<Vec<u8>> {
        let mut result = Vec::with_capacity(data.len() / 2);
        for i in 0..data.len() / 2 {
            let chunk = &data[(i * 2)..(i * 2 + 2)];
            if let Ok(byte) = u8::from_str_radix(chunk, 16) {
                result.push(byte);
            } else {
                return Err(StorageError::CouldNotStoreData(format!(
                    "Could not convert to byte: {}",
                    chunk
                )));
            }
        }
        Ok(result)
    }

    fn bytes_to_string(data: &[u8]) -> StorageResult<String> {
        let mut result = String::with_capacity(data.len() * 2);
        for byte in data {
            if write!(&mut result, "{:02X}", byte).is_err() {
                return Err(StorageError::CouldNotStoreData(format!(
                    "Could not convert byte: {}",
                    byte
                )));
            }
        }
        Ok(result)
    }
}