matrix_sdk_ffi/
chunk_iterator.rs

1//! A generic `ChunkIterator` that operates over a `Vec`.
2//!
3//! This type is not designed to work over FFI, but it can be embedded inside an
4//! `uniffi::Object` for example.
5
6use std::{cmp, mem, sync::RwLock};
7
8pub struct ChunkIterator<T> {
9    items: RwLock<Vec<T>>,
10}
11
12impl<T> ChunkIterator<T> {
13    pub fn new(items: Vec<T>) -> Self {
14        Self { items: RwLock::new(items) }
15    }
16
17    pub fn len(&self) -> u32 {
18        self.items.read().unwrap().len().try_into().unwrap()
19    }
20
21    pub fn next(&self, chunk_size: u32) -> Option<Vec<T>> {
22        if self.items.read().unwrap().is_empty() {
23            None
24        } else if chunk_size == 0 {
25            Some(Vec::new())
26        } else {
27            let mut items = self.items.write().unwrap();
28
29            // Compute the `chunk_size`.
30            let chunk_size = cmp::min(items.len(), chunk_size.try_into().unwrap());
31            // Split the items vector.
32            let mut tail = items.split_off(chunk_size);
33            // `Vec::split_off` returns the tail, and `items` contains the head. Let's
34            // swap them.
35            mem::swap(&mut tail, &mut items);
36            // Finally, let's rename `tail` to `head`.
37            let head = tail;
38
39            Some(head)
40        }
41    }
42}
43
44#[cfg(test)]
45mod tests {
46    use super::ChunkIterator;
47
48    #[test]
49    fn test_len() {
50        assert_eq!(ChunkIterator::<u8>::new(vec![1, 2, 3]).len(), 3);
51        assert_eq!(ChunkIterator::<u8>::new(vec![]).len(), 0);
52    }
53
54    #[test]
55    fn test_next() {
56        let iterator = ChunkIterator::new(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
57
58        assert_eq!(iterator.next(3), Some(vec![1, 2, 3]));
59        assert_eq!(iterator.next(5), Some(vec![4, 5, 6, 7, 8]));
60        assert_eq!(iterator.next(0), Some(vec![]));
61        assert_eq!(iterator.next(1), Some(vec![9]));
62        assert_eq!(iterator.next(3), Some(vec![10, 11]));
63        assert_eq!(iterator.next(2), None);
64        assert_eq!(iterator.next(2), None);
65    }
66}