use std::cell::RefCell;
pub struct ProgressiveLoader<T> {
items: Vec<T>,
loaded: RefCell<usize>,
chunk_size: usize,
}
impl<T: Clone> ProgressiveLoader<T> {
pub fn new(items: Vec<T>, chunk_size: usize) -> Self {
Self {
items,
loaded: RefCell::new(0),
chunk_size: chunk_size.max(1),
}
}
pub fn total(&self) -> usize {
self.items.len()
}
pub fn loaded_count(&self) -> usize {
*self.loaded.borrow()
}
pub fn is_complete(&self) -> bool {
*self.loaded.borrow() >= self.items.len()
}
pub fn progress(&self) -> f32 {
if self.items.is_empty() {
1.0
} else {
*self.loaded.borrow() as f32 / self.items.len() as f32
}
}
pub fn load_next(&self) -> Vec<T> {
let start = *self.loaded.borrow();
let end = (start + self.chunk_size).min(self.items.len());
if start >= self.items.len() {
return Vec::new();
}
let chunk: Vec<T> = self.items[start..end].to_vec();
*self.loaded.borrow_mut() = end;
chunk
}
pub fn loaded_items(&self) -> Vec<T> {
let count = *self.loaded.borrow();
self.items[..count].to_vec()
}
pub fn reset(&self) {
*self.loaded.borrow_mut() = 0;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_progressive_loader_new() {
let loader = ProgressiveLoader::new(vec![1, 2, 3, 4, 5], 2);
assert_eq!(loader.total(), 5);
assert_eq!(loader.loaded_count(), 0);
assert!(!loader.is_complete());
}
#[test]
fn test_progressive_loader_total() {
let loader = ProgressiveLoader::new(vec![1, 2, 3], 1);
assert_eq!(loader.total(), 3);
let empty: ProgressiveLoader<i32> = ProgressiveLoader::new(vec![], 1);
assert_eq!(empty.total(), 0);
}
#[test]
fn test_progressive_loader_loaded_count() {
let loader = ProgressiveLoader::new(vec![1, 2, 3, 4, 5], 2);
assert_eq!(loader.loaded_count(), 0);
loader.load_next();
assert_eq!(loader.loaded_count(), 2);
loader.load_next();
assert_eq!(loader.loaded_count(), 4);
loader.load_next();
assert_eq!(loader.loaded_count(), 5);
}
#[test]
fn test_progressive_loader_is_complete() {
let loader = ProgressiveLoader::new(vec![1, 2, 3], 3);
assert!(!loader.is_complete());
loader.load_next();
assert!(loader.is_complete());
}
#[test]
fn test_progressive_loader_progress() {
let loader = ProgressiveLoader::new(vec![1, 2, 3, 4, 5], 2);
assert_eq!(loader.progress(), 0.0);
loader.load_next();
assert_eq!(loader.progress(), 2.0 / 5.0);
loader.load_next();
assert_eq!(loader.progress(), 4.0 / 5.0);
loader.load_next();
assert_eq!(loader.progress(), 1.0);
}
#[test]
fn test_progressive_loader_progress_empty() {
let loader: ProgressiveLoader<i32> = ProgressiveLoader::new(vec![], 1);
assert_eq!(loader.progress(), 1.0);
}
#[test]
fn test_progressive_loader_load_next() {
let loader = ProgressiveLoader::new(vec![1, 2, 3, 4, 5], 2);
let chunk1 = loader.load_next();
assert_eq!(chunk1, vec![1, 2]);
let chunk2 = loader.load_next();
assert_eq!(chunk2, vec![3, 4]);
let chunk3 = loader.load_next();
assert_eq!(chunk3, vec![5]);
let chunk4 = loader.load_next();
assert!(chunk4.is_empty());
}
#[test]
fn test_progressive_loader_loaded_items() {
let loader = ProgressiveLoader::new(vec![1, 2, 3, 4, 5], 2);
assert_eq!(loader.loaded_items(), vec![] as Vec<i32>);
loader.load_next();
assert_eq!(loader.loaded_items(), vec![1, 2]);
loader.load_next();
assert_eq!(loader.loaded_items(), vec![1, 2, 3, 4]);
loader.load_next();
assert_eq!(loader.loaded_items(), vec![1, 2, 3, 4, 5]);
}
#[test]
fn test_progressive_loader_reset() {
let loader = ProgressiveLoader::new(vec![1, 2, 3, 4, 5], 2);
loader.load_next();
loader.load_next();
assert_eq!(loader.loaded_count(), 4);
loader.reset();
assert_eq!(loader.loaded_count(), 0);
assert!(!loader.is_complete());
}
#[test]
fn test_progressive_loader_with_strings() {
let loader = ProgressiveLoader::new(vec!["a", "b", "c"], 2);
let chunk1 = loader.load_next();
assert_eq!(chunk1, vec!["a", "b"]);
let chunk2 = loader.load_next();
assert_eq!(chunk2, vec!["c"]);
}
#[test]
fn test_progressive_loader_chunk_size_minimum() {
let loader = ProgressiveLoader::new(vec![1, 2, 3], 0);
let chunk1 = loader.load_next();
assert_eq!(chunk1, vec![1]);
assert_eq!(loader.loaded_count(), 1);
}
#[test]
fn test_progressive_loader_empty_vec() {
let loader: ProgressiveLoader<i32> = ProgressiveLoader::new(vec![], 1);
assert!(loader.is_complete());
assert_eq!(loader.load_next(), Vec::<i32>::new());
assert_eq!(loader.loaded_items(), Vec::<i32>::new());
}
}