diem_secure_storage/
namespaced_storage.rs

1// Copyright (c) The Diem Core Contributors
2// SPDX-License-Identifier: Apache-2.0
3
4// Copyright 2021 Conflux Foundation. All rights reserved.
5// Conflux is free software and distributed under GNU General Public License.
6// See http://www.gnu.org/licenses/
7
8use crate::{CryptoKVStorage, Error, GetResponse, KVStorage, Storage};
9use serde::{de::DeserializeOwned, Serialize};
10
11/// This provides a light wrapper around KV storages to support a namespace.
12/// That namespace is effectively prefixing all keys with then namespace value
13/// and "/" so a namespace of foo and a key of bar becomes "foo/bar". Without a
14/// namespace, the key would just be "bar". This matches how this library
15/// implements namespaces for Vault.
16pub struct NamespacedStorage {
17    namespace: String,
18    inner: Box<Storage>,
19}
20
21impl KVStorage for NamespacedStorage {
22    fn available(&self) -> Result<(), Error> { self.inner.available() }
23
24    fn get<T: DeserializeOwned>(
25        &self, key: &str,
26    ) -> Result<GetResponse<T>, Error> {
27        self.inner.get(&self.ns_name(key))
28    }
29
30    fn set<T: Serialize>(&mut self, key: &str, value: T) -> Result<(), Error> {
31        self.inner.set(&self.ns_name(key), value)
32    }
33
34    /// Note: This is not a namespace function
35    #[cfg(any(test, feature = "testing"))]
36    fn reset_and_clear(&mut self) -> Result<(), Error> {
37        self.inner.reset_and_clear()
38    }
39}
40
41impl NamespacedStorage {
42    pub fn new(storage: Storage, namespace: String) -> Self {
43        NamespacedStorage {
44            namespace,
45            inner: Box::new(storage),
46        }
47    }
48
49    fn ns_name(&self, key: &str) -> String {
50        format!("{}/{}", self.namespace, key)
51    }
52}
53
54impl CryptoKVStorage for NamespacedStorage {}
55
56#[cfg(test)]
57mod test {
58    use super::*;
59    use crate::OnDiskStorage;
60    use diem_temppath::TempPath;
61
62    #[test]
63    fn test_different_namespaces() {
64        let ns0 = "ns0";
65        let ns1 = "ns1";
66        let key = "key";
67
68        let path_buf = TempPath::new().path().to_path_buf();
69
70        let mut default = OnDiskStorage::new(path_buf.clone());
71
72        let storage =
73            Storage::OnDiskStorage(OnDiskStorage::new(path_buf.clone()));
74        let mut nss0 = NamespacedStorage::new(storage, ns0.into());
75
76        let storage = Storage::OnDiskStorage(OnDiskStorage::new(path_buf));
77        let mut nss1 = NamespacedStorage::new(storage, ns1.into());
78
79        default.set(key, 0).unwrap();
80        nss0.set(key, 1).unwrap();
81        nss1.set(key, 2).unwrap();
82
83        assert_eq!(default.get::<u64>(key).unwrap().value, 0);
84        assert_eq!(nss0.get::<u64>(key).unwrap().value, 1);
85        assert_eq!(nss1.get::<u64>(key).unwrap().value, 2);
86    }
87
88    #[test]
89    fn test_shared_namespace() {
90        let ns = "ns";
91        let key = "key";
92
93        let path_buf = TempPath::new().path().to_path_buf();
94
95        let default =
96            Storage::OnDiskStorage(OnDiskStorage::new(path_buf.clone()));
97
98        let storage =
99            Storage::OnDiskStorage(OnDiskStorage::new(path_buf.clone()));
100        let mut nss = NamespacedStorage::new(storage, ns.into());
101
102        let storage = Storage::OnDiskStorage(OnDiskStorage::new(path_buf));
103        let another_nss = NamespacedStorage::new(storage, ns.into());
104
105        nss.set(key, 1).unwrap();
106        default.get::<u64>(key).unwrap_err();
107        assert_eq!(nss.get::<u64>(key).unwrap().value, 1);
108        assert_eq!(another_nss.get::<u64>(key).unwrap().value, 1);
109    }
110}