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
// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::Error;
use enum_dispatch::enum_dispatch;
use serde::{de::DeserializeOwned, Deserialize, Serialize};

/// A secure key/value storage engine. Create takes a policy that is enforced internally by the
/// actual backend. The policy contains public identities that the backend can translate into a
/// unique and private token for another service. Hence get and set internally will pass the
/// current service private token to the backend to gain its permissions.
#[enum_dispatch]
pub trait KVStorage {
    /// Returns an error if the backend service is not online and available.
    fn available(&self) -> Result<(), Error>;

    /// Retrieves a value from storage and fails if the backend is unavailable or the process has
    /// invalid permissions.
    fn get<T: DeserializeOwned>(&self, key: &str) -> Result<GetResponse<T>, Error>;

    /// Sets a value in storage and fails if the backend is unavailable or the process has
    /// invalid permissions.
    fn set<T: Serialize>(&mut self, key: &str, value: T) -> Result<(), Error>;

    /// Resets and clears all data held in the storage engine.
    /// Note: this should only be exposed and used for testing. Resetting the storage engine is not
    /// something that should be supported in production.
    #[cfg(any(test, feature = "testing"))]
    fn reset_and_clear(&mut self) -> Result<(), Error>;
}

impl<'a, S> KVStorage for &'a mut S
where
    S: KVStorage,
{
    fn available(&self) -> Result<(), Error> {
        S::available(self)
    }

    fn get<T: DeserializeOwned>(&self, key: &str) -> Result<GetResponse<T>, Error> {
        S::get(self, key)
    }

    fn set<T: Serialize>(&mut self, key: &str, value: T) -> Result<(), Error> {
        S::set(self, key, value)
    }

    #[cfg(any(test, feature = "testing"))]
    fn reset_and_clear(&mut self) -> Result<(), Error> {
        S::reset_and_clear(self)
    }
}

/// A container for a get response that contains relevant metadata and the value stored at the
/// given key.
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize)]
#[serde(tag = "data")]
pub struct GetResponse<T> {
    /// Time since Unix Epoch in seconds.
    pub last_update: u64,
    /// Value stored at the provided key
    pub value: T,
}

impl<T> GetResponse<T> {
    /// Creates a GetResponse
    pub fn new(value: T, last_update: u64) -> Self {
        Self { last_update, value }
    }
}