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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
use super::SOURCE_GUEST;
use crate::do_host_call;
use crate::errors::{self, ErrorKind};
use crate::Result;
use codec::keyvalue::{
    AddRequest, AddResponse, DelRequest, GetRequest, GetResponse, ListPushRequest,
    ListRangeRequest, ListRangeResponse, ListResponse, SetRequest, SetResponse,
};
use prost::Message;
use wascap_codec as codec;
use wascap_codec::AsCommand;

pub trait KeyValueStore {
    fn get(&self, key: &str) -> Result<(String, bool)>;
    fn set(&self, key: &str, value: &str) -> Result<()>;
    fn atomic_add(&self, key: &str, value: i32) -> Result<i32>;
    fn list_add(&self, key: &str, item: &str) -> Result<usize>;
    fn del_key(&self, key: &str) -> Result<()>;
    fn list_range(&self, key: &str, start: isize, stop_inclusive: isize) -> Result<Vec<String>>;
}

pub struct HostKeyValueStore {}

const TARGET_KEYVALUE: &'static str = "wascap:keyvalue";

impl HostKeyValueStore {
    pub fn new() -> HostKeyValueStore {
        HostKeyValueStore {}
    }
}

impl KeyValueStore for HostKeyValueStore {
    fn get(&self, key: &str) -> Result<(String, bool)> {
        let cmd = GetRequest {
            key: key.to_string(),
        }
        .as_command(SOURCE_GUEST, TARGET_KEYVALUE);
        do_host_call(&cmd).map(|evt| {
            let resp = GetResponse::decode(&evt.payload.unwrap().value).unwrap();
            (resp.value, resp.exists)
        })
    }

    fn set(&self, key: &str, value: &str) -> Result<()> {
        let cmd = SetRequest {
            key: key.to_string(),
            value: value.to_string(),
        }
        .as_command(SOURCE_GUEST, TARGET_KEYVALUE);
        do_host_call(&cmd).map(|evt| ())
    }

    fn atomic_add(&self, key: &str, value: i32) -> Result<i32> {
        let cmd = AddRequest {
            key: key.to_string(),
            value: value,
        }
        .as_command(SOURCE_GUEST, TARGET_KEYVALUE);
        do_host_call(&cmd).map(|evt| {
            let resp = AddResponse::decode(&evt.payload.unwrap().value).unwrap();
            resp.value
        })
    }

    fn list_add(&self, key: &str, item: &str) -> Result<usize> {
        let cmd = ListPushRequest {
            key: key.to_string(),
            value: item.to_string(),
        }
        .as_command(SOURCE_GUEST, TARGET_KEYVALUE);
        do_host_call(&cmd).map(|evt| {
            let resp = ListResponse::decode(&evt.payload.unwrap().value).unwrap();
            resp.new_count as usize
        })
    }

    fn del_key(&self, key: &str) -> Result<()> {
        let cmd = DelRequest {
            key: key.to_string(),
        }
        .as_command(SOURCE_GUEST, TARGET_KEYVALUE);
        do_host_call(&cmd).map(|evt| ())
    }

    fn list_range(&self, key: &str, start: isize, stop_inclusive: isize) -> Result<Vec<String>> {
        let cmd = ListRangeRequest {
            key: key.to_string(),
            start: start as i32,
            stop: stop_inclusive as i32,
        }
        .as_command(SOURCE_GUEST, TARGET_KEYVALUE);
        do_host_call(&cmd).map(|evt| {
            let resp = ListRangeResponse::decode(&evt.payload.unwrap().value).unwrap();
            resp.values
        })
    }
}