Coverage Report

Created: 2026-04-09 06:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/wasefire-store-0.2.4/src/fragment.rs
Line
Count
Source
1
// Copyright 2021 Google LLC
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
//! Support for fragmented entries.
16
//!
17
//! This module permits to handle entries larger than the [maximum value
18
//! length](Store::max_value_length) by storing ordered consecutive fragments in a sequence of keys.
19
//! The first keys hold fragments of maximal length, followed by a possibly partial fragment. The
20
//! remaining keys are not used.
21
22
use alloc::vec::Vec;
23
use core::ops::Range;
24
25
use crate::{Storage, Store, StoreError, StoreHandle, StoreResult, StoreUpdate};
26
27
/// Represents a sequence of keys.
28
#[allow(clippy::len_without_is_empty)]
29
pub trait Keys {
30
    /// Returns the number of keys.
31
    fn len(&self) -> usize;
32
33
    /// Returns the position of a key in the sequence.
34
    fn pos(&self, key: usize) -> Option<usize>;
35
36
    /// Returns the key of a position in the sequence.
37
    ///
38
    /// # Preconditions
39
    ///
40
    /// The position must be within the length: `pos` < [`Self::len`].
41
    fn key(&self, pos: usize) -> usize;
42
}
43
44
impl Keys for Range<usize> {
45
0
    fn len(&self) -> usize {
46
0
        self.end.saturating_sub(self.start)
47
0
    }
48
49
0
    fn pos(&self, key: usize) -> Option<usize> {
50
0
        if self.start <= key && key < self.end {
51
0
            Some(key - self.start)
52
        } else {
53
0
            None
54
        }
55
0
    }
56
57
0
    fn key(&self, pos: usize) -> usize {
58
0
        debug_assert!(pos < Keys::len(self));
59
0
        self.start + pos
60
0
    }
61
}
62
63
/// Reads the concatenated value of a sequence of keys.
64
0
pub fn read(store: &Store<impl Storage>, keys: &impl Keys) -> StoreResult<Option<Vec<u8>>> {
65
0
    let handles = get_handles(store, keys)?;
66
0
    if handles.is_empty() {
67
0
        return Ok(None);
68
0
    }
69
0
    let mut result = Vec::with_capacity(handles.len() * store.max_value_length());
70
0
    for handle in handles {
71
0
        result.extend(handle.get_value(store)?);
72
    }
73
0
    Ok(Some(result))
74
0
}
75
76
/// Reads a range from the concatenated value of a sequence of keys.
77
///
78
/// This is equivalent to calling [`read`] then taking the range except that:
79
/// - Only the needed chunks are read.
80
/// - The range is truncated to fit in the value.
81
0
pub fn read_range(
82
0
    store: &Store<impl Storage>, keys: &impl Keys, range: Range<usize>,
83
0
) -> StoreResult<Option<Vec<u8>>> {
84
0
    let range_len = match range.end.checked_sub(range.start) {
85
0
        None => return Err(StoreError::InvalidArgument),
86
0
        Some(x) => x,
87
    };
88
0
    let handles = get_handles(store, keys)?;
89
0
    if handles.is_empty() {
90
0
        return Ok(None);
91
0
    }
92
0
    let mut result = Vec::with_capacity(range_len);
93
0
    let mut offset = 0;
94
0
    for handle in handles {
95
0
        let start = range.start.saturating_sub(offset);
96
0
        let length = handle.get_length(store)?;
97
0
        let end = core::cmp::min(range.end.saturating_sub(offset), length);
98
0
        offset += length;
99
0
        if start < end {
100
0
            result.extend(&handle.get_value(store)?[start .. end]);
101
0
        }
102
    }
103
0
    Ok(Some(result))
104
0
}
105
106
/// Writes a value to a sequence of keys as chunks.
107
0
pub fn write(store: &mut Store<impl Storage>, keys: &impl Keys, value: &[u8]) -> StoreResult<()> {
108
0
    let handles = get_handles(store, keys)?;
109
0
    let keys_len = keys.len();
110
0
    let mut updates = Vec::with_capacity(keys_len);
111
0
    let mut chunks = value.chunks(store.max_value_length());
112
0
    for pos in 0 .. keys_len {
113
0
        let key = keys.key(pos);
114
0
        match (handles.get(pos), chunks.next()) {
115
            // No existing handle and no new chunk: nothing to do.
116
0
            (None, None) => (),
117
            // Existing handle and no new chunk: remove old handle.
118
0
            (Some(_), None) => updates.push(StoreUpdate::Remove { key }),
119
            // Existing handle with same value as new chunk: nothing to do.
120
0
            (Some(handle), Some(value)) if handle.get_value(store)? == value => (),
121
            // New chunk: Write (or overwrite) the new value.
122
0
            (_, Some(value)) => updates.push(StoreUpdate::Insert { key, value }),
123
        }
124
    }
125
0
    if chunks.next().is_some() {
126
        // The value is too long.
127
0
        return Err(StoreError::InvalidArgument);
128
0
    }
129
0
    store.transaction(&updates)
130
0
}
131
132
/// Deletes the value of a sequence of keys.
133
0
pub fn delete(store: &mut Store<impl Storage>, keys: &impl Keys) -> StoreResult<()> {
134
0
    let updates: Vec<StoreUpdate<Vec<u8>>> = get_handles(store, keys)?
135
0
        .iter()
136
0
        .map(|handle| StoreUpdate::Remove { key: handle.get_key() })
137
0
        .collect();
138
0
    store.transaction(&updates)
139
0
}
140
141
/// Returns the handles of a sequence of keys.
142
///
143
/// The handles are truncated to the keys that are present.
144
0
fn get_handles(store: &Store<impl Storage>, keys: &impl Keys) -> StoreResult<Vec<StoreHandle>> {
145
0
    let keys_len = keys.len();
146
0
    let mut handles: Vec<Option<StoreHandle>> = vec![None; keys_len];
147
0
    for handle in store.iter()? {
148
0
        let handle = handle?;
149
0
        let pos = match keys.pos(handle.get_key()) {
150
0
            Some(pos) => pos,
151
0
            None => continue,
152
        };
153
0
        if pos >= keys_len {
154
0
            return Err(StoreError::InvalidArgument);
155
0
        }
156
0
        if let Some(old_handle) = &handles[pos] {
157
0
            if old_handle.get_key() != handle.get_key() {
158
                // The user provided a non-injective `pos` function.
159
0
                return Err(StoreError::InvalidArgument);
160
            } else {
161
0
                return Err(StoreError::InvalidStorage);
162
            }
163
0
        }
164
0
        handles[pos] = Some(handle);
165
    }
166
0
    let num_handles = handles.iter().filter(|x| x.is_some()).count();
167
0
    let mut result = Vec::with_capacity(num_handles);
168
0
    for (i, handle) in handles.into_iter().enumerate() {
169
0
        match (i < num_handles, handle) {
170
0
            (true, Some(handle)) => result.push(handle),
171
0
            (false, None) => (),
172
            // We should have `num_handles` Somes followed by Nones.
173
0
            _ => return Err(StoreError::InvalidStorage),
174
        }
175
    }
176
0
    Ok(result)
177
0
}
178
179
#[cfg(test)]
180
mod tests {
181
    use super::*;
182
    use crate::test::MINIMAL;
183
184
    #[test]
185
    fn read_empty_entry() {
186
        let store = MINIMAL.new_store();
187
        assert_eq!(read(&store, &(0 .. 4)), Ok(None));
188
    }
189
190
    #[test]
191
    fn read_single_chunk() {
192
        let mut store = MINIMAL.new_store();
193
        let value = b"hello".to_vec();
194
        assert_eq!(store.insert(0, &value), Ok(()));
195
        assert_eq!(read(&store, &(0 .. 4)), Ok(Some(value)));
196
    }
197
198
    #[test]
199
    fn read_multiple_chunks() {
200
        let mut store = MINIMAL.new_store();
201
        let value: Vec<_> = (0 .. 60).collect();
202
        assert_eq!(store.insert(0, &value[.. 52]), Ok(()));
203
        assert_eq!(store.insert(1, &value[52 ..]), Ok(()));
204
        assert_eq!(read(&store, &(0 .. 4)), Ok(Some(value)));
205
    }
206
207
    #[test]
208
    fn read_range_first_chunk() {
209
        let mut store = MINIMAL.new_store();
210
        let value: Vec<_> = (0 .. 60).collect();
211
        assert_eq!(store.insert(0, &value[.. 52]), Ok(()));
212
        assert_eq!(store.insert(1, &value[52 ..]), Ok(()));
213
        assert_eq!(read_range(&store, &(0 .. 4), 0 .. 10), Ok(Some((0 .. 10).collect())));
214
        assert_eq!(read_range(&store, &(0 .. 4), 10 .. 20), Ok(Some((10 .. 20).collect())));
215
        assert_eq!(read_range(&store, &(0 .. 4), 40 .. 52), Ok(Some((40 .. 52).collect())));
216
    }
217
218
    #[test]
219
    fn read_range_second_chunk() {
220
        let mut store = MINIMAL.new_store();
221
        let value: Vec<_> = (0 .. 60).collect();
222
        assert_eq!(store.insert(0, &value[.. 52]), Ok(()));
223
        assert_eq!(store.insert(1, &value[52 ..]), Ok(()));
224
        assert_eq!(read_range(&store, &(0 .. 4), 52 .. 53), Ok(Some(vec![52])));
225
        assert_eq!(read_range(&store, &(0 .. 4), 53 .. 54), Ok(Some(vec![53])));
226
        assert_eq!(read_range(&store, &(0 .. 4), 59 .. 60), Ok(Some(vec![59])));
227
    }
228
229
    #[test]
230
    fn read_range_both_chunks() {
231
        let mut store = MINIMAL.new_store();
232
        let value: Vec<_> = (0 .. 60).collect();
233
        assert_eq!(store.insert(0, &value[.. 52]), Ok(()));
234
        assert_eq!(store.insert(1, &value[52 ..]), Ok(()));
235
        assert_eq!(read_range(&store, &(0 .. 4), 40 .. 60), Ok(Some((40 .. 60).collect())));
236
        assert_eq!(read_range(&store, &(0 .. 4), 0 .. 60), Ok(Some((0 .. 60).collect())));
237
    }
238
239
    #[test]
240
    fn read_range_outside() {
241
        let mut store = MINIMAL.new_store();
242
        let value: Vec<_> = (0 .. 60).collect();
243
        assert_eq!(store.insert(0, &value[.. 52]), Ok(()));
244
        assert_eq!(store.insert(1, &value[52 ..]), Ok(()));
245
        assert_eq!(read_range(&store, &(0 .. 4), 40 .. 100), Ok(Some((40 .. 60).collect())));
246
        assert_eq!(read_range(&store, &(0 .. 4), 60 .. 100), Ok(Some(vec![])));
247
    }
248
249
    #[test]
250
    fn write_single_chunk() {
251
        let mut store = MINIMAL.new_store();
252
        let value = b"hello".to_vec();
253
        assert_eq!(write(&mut store, &(0 .. 4), &value), Ok(()));
254
        assert_eq!(store.find(0), Ok(Some(value)));
255
        assert_eq!(store.find(1), Ok(None));
256
        assert_eq!(store.find(2), Ok(None));
257
        assert_eq!(store.find(3), Ok(None));
258
    }
259
260
    #[test]
261
    fn write_multiple_chunks() {
262
        let mut store = MINIMAL.new_store();
263
        let value: Vec<_> = (0 .. 60).collect();
264
        assert_eq!(write(&mut store, &(0 .. 4), &value), Ok(()));
265
        assert_eq!(store.find(0), Ok(Some((0 .. 52).collect())));
266
        assert_eq!(store.find(1), Ok(Some((52 .. 60).collect())));
267
        assert_eq!(store.find(2), Ok(None));
268
        assert_eq!(store.find(3), Ok(None));
269
    }
270
271
    #[test]
272
    fn overwrite_less_chunks() {
273
        let mut store = MINIMAL.new_store();
274
        let value: Vec<_> = (0 .. 60).collect();
275
        assert_eq!(store.insert(0, &value[.. 52]), Ok(()));
276
        assert_eq!(store.insert(1, &value[52 ..]), Ok(()));
277
        let value: Vec<_> = (42 .. 69).collect();
278
        assert_eq!(write(&mut store, &(0 .. 4), &value), Ok(()));
279
        assert_eq!(store.find(0), Ok(Some((42 .. 69).collect())));
280
        assert_eq!(store.find(1), Ok(None));
281
        assert_eq!(store.find(2), Ok(None));
282
        assert_eq!(store.find(3), Ok(None));
283
    }
284
285
    #[test]
286
    fn overwrite_needed_chunks() {
287
        let mut store = MINIMAL.new_store();
288
        let mut value: Vec<_> = (0 .. 60).collect();
289
        assert_eq!(store.insert(0, &value[.. 52]), Ok(()));
290
        assert_eq!(store.insert(1, &value[52 ..]), Ok(()));
291
        // Current lifetime is 2 words of overhead (2 insert) and 60 bytes of data.
292
        let mut lifetime = 2 + 60 / 4;
293
        assert_eq!(store.lifetime().unwrap().used(), lifetime);
294
        // Update the value.
295
        value.extend(60 .. 80);
296
        assert_eq!(write(&mut store, &(0 .. 4), &value), Ok(()));
297
        // Added lifetime is 1 word of overhead (1 insert) and (80 - 52) bytes of data.
298
        lifetime += 1 + (80 - 52) / 4;
299
        assert_eq!(store.lifetime().unwrap().used(), lifetime);
300
    }
301
302
    #[test]
303
    fn delete_empty() {
304
        let mut store = MINIMAL.new_store();
305
        assert_eq!(delete(&mut store, &(0 .. 4)), Ok(()));
306
        assert_eq!(store.find(0), Ok(None));
307
        assert_eq!(store.find(1), Ok(None));
308
        assert_eq!(store.find(2), Ok(None));
309
        assert_eq!(store.find(3), Ok(None));
310
    }
311
312
    #[test]
313
    fn delete_chunks() {
314
        let mut store = MINIMAL.new_store();
315
        let value: Vec<_> = (0 .. 60).collect();
316
        assert_eq!(store.insert(0, &value[.. 52]), Ok(()));
317
        assert_eq!(store.insert(1, &value[52 ..]), Ok(()));
318
        assert_eq!(delete(&mut store, &(0 .. 4)), Ok(()));
319
        assert_eq!(store.find(0), Ok(None));
320
        assert_eq!(store.find(1), Ok(None));
321
        assert_eq!(store.find(2), Ok(None));
322
        assert_eq!(store.find(3), Ok(None));
323
    }
324
}