aingle_rkv/store/
integer.rs

1// Copyright 2018-2019 Mozilla
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
4// this file except in compliance with the License. You may obtain a copy of the
5// License at http://www.apache.org/licenses/LICENSE-2.0
6// Unless required by applicable law or agreed to in writing, software distributed
7// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
8// CONDITIONS OF ANY KIND, either express or implied. See the License for the
9// specific language governing permissions and limitations under the License.
10
11use std::marker::PhantomData;
12
13use bincode::{serialize, deserialize};
14
15use serde::{de::DeserializeOwned, Serialize};
16
17use aingle_lmdb::Database;
18
19use crate::error::{
20    DataError,
21    StoreError,
22};
23
24use crate::readwrite::{
25    Readable,
26    Writer,
27};
28
29use crate::value::Value;
30
31use crate::store::single::{
32    Iter,
33    SingleStore,
34};
35
36pub trait EncodableKey: Sized {
37    fn to_bytes(&self) -> Result<Vec<u8>, DataError>;
38    fn from_bytes(bytes: &[u8]) -> Result<Self, DataError>;
39}
40
41pub trait PrimitiveInt: Copy + EncodableKey {}
42
43impl PrimitiveInt for u32 {}
44
45impl<T> EncodableKey for T
46where
47    T: Serialize + DeserializeOwned
48{
49    fn to_bytes(&self) -> Result<Vec<u8>, DataError> {
50        serialize(self) // TODO: limited key length.
51            .map_err(Into::into)
52    }
53
54    fn from_bytes(bytes: &[u8]) -> Result<Self, DataError> {
55        deserialize(bytes).map_err(Into::into)
56    }
57}
58
59pub(crate) struct Key<K> {
60    bytes: Vec<u8>,
61    phantom: PhantomData<K>,
62}
63
64impl<K> AsRef<[u8]> for Key<K>
65where
66    K: EncodableKey,
67{
68    fn as_ref(&self) -> &[u8] {
69        self.bytes.as_ref()
70    }
71}
72
73impl<K> Key<K>
74where
75    K: EncodableKey,
76{
77    #[allow(clippy::new_ret_no_self)]
78    pub(crate) fn new(k: &K) -> Result<Key<K>, DataError> {
79        Ok(Key {
80            bytes: k.to_bytes()?,
81            phantom: PhantomData,
82        })
83    }
84}
85
86#[derive(Copy, Clone)]
87pub struct IntegerStore<K>
88where
89    K: PrimitiveInt,
90{
91    inner: SingleStore,
92    phantom: PhantomData<K>,
93}
94
95impl<K> IntegerStore<K>
96where
97    K: PrimitiveInt,
98{
99    pub(crate) fn new(db: Database) -> IntegerStore<K> {
100        IntegerStore {
101            inner: SingleStore::new(db),
102            phantom: PhantomData,
103        }
104    }
105
106    pub fn get<'env, T: Readable>(&self, reader: &'env T, k: K) -> Result<Option<Value<'env>>, StoreError> {
107        self.inner.get(reader, Key::new(&k)?)
108    }
109
110    pub fn put(&self, writer: &mut Writer, k: K, v: &Value) -> Result<(), StoreError> {
111        self.inner.put(writer, Key::new(&k)?, v)
112    }
113
114    pub fn delete(&self, writer: &mut Writer, k: K) -> Result<(), StoreError> {
115        self.inner.delete(writer, Key::new(&k)?)
116    }
117
118    pub fn clear(&self, writer: &mut Writer) -> Result<(), StoreError> {
119        self.inner.clear(writer)
120    }
121
122    pub fn iter_start<'env, T: Readable>(&self, reader: &'env T) -> Result<Iter<'env>, StoreError> {
123        self.inner.iter_start(reader)
124    }
125
126    pub fn iter_end<'env, T: Readable>(&self, reader: &'env T) -> Result<Iter<'env>, StoreError> {
127        self.inner.iter_end(reader)
128    }
129
130    pub fn iter_from<'env, T: Readable>(&self, reader: &'env T, k: K) -> Result<Iter<'env>, StoreError> {
131        self.inner.iter_from(reader, Key::new(&k)?)
132    }
133}
134
135#[cfg(test)]
136mod tests {
137    use std::fs;
138    use tempfile::Builder;
139
140    use super::*;
141    use crate::*;
142
143    #[test]
144    fn test_integer_keys() {
145        let root = Builder::new().prefix("test_integer_keys").tempdir().expect("tempdir");
146        fs::create_dir_all(root.path()).expect("dir created");
147        let k = Rkv::new(root.path()).expect("new succeeded");
148        let s = k.open_integer("s", StoreOptions::create()).expect("open");
149
150        macro_rules! test_integer_keys {
151            ($type:ty, $key:expr) => {{
152                let mut writer = k.write().expect("writer");
153
154                s.put(&mut writer, $key, &Value::Str("hello!")).expect("write");
155                assert_eq!(s.get(&writer, $key).expect("read"), Some(Value::Str("hello!")));
156                writer.commit().expect("committed");
157
158                let reader = k.read().expect("reader");
159                assert_eq!(s.get(&reader, $key).expect("read"), Some(Value::Str("hello!")));
160            }};
161        }
162
163        test_integer_keys!(u32, std::u32::MIN);
164        test_integer_keys!(u32, std::u32::MAX);
165    }
166
167    #[test]
168    fn test_clear() {
169        let root = Builder::new().prefix("test_integer_clear").tempdir().expect("tempdir");
170        fs::create_dir_all(root.path()).expect("dir created");
171        let k = Rkv::new(root.path()).expect("new succeeded");
172        let s = k.open_integer("s", StoreOptions::create()).expect("open");
173
174        {
175            let mut writer = k.write().expect("writer");
176            s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
177            s.put(&mut writer, 2, &Value::Str("hello!")).expect("write");
178            s.put(&mut writer, 3, &Value::Str("hello!")).expect("write");
179            writer.commit().expect("committed");
180        }
181
182        {
183            let mut writer = k.write().expect("writer");
184            s.clear(&mut writer).expect("cleared");
185            writer.commit().expect("committed");
186
187            let reader = k.read().expect("reader");
188            assert_eq!(s.get(&reader, 1).expect("read"), None);
189            assert_eq!(s.get(&reader, 2).expect("read"), None);
190            assert_eq!(s.get(&reader, 3).expect("read"), None);
191        }
192    }
193}