use anyhow::Result;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct Chunk {
pub index: usize,
pub start: u64,
pub end: u64,
pub completed: bool,
#[serde(default)]
pub current_offset: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DownloadState {
pub url: String,
pub chunks: Vec<Chunk>,
}
pub async fn save_state(state: &DownloadState, filename: &str) -> Result<()> {
let json = serde_json::to_string_pretty(state)?;
tokio::fs::write(filename, json).await?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::tempdir;
#[tokio::test] async fn test_save_and_load_state() -> Result<()> {
let dir = tempdir()?; let file_path = dir.path().join("test.state.json");
let path_str = file_path.to_str().unwrap();
let state = DownloadState {
url: "http://example.com".to_string(),
chunks: vec![
Chunk {
index: 0,
start: 0,
end: 10,
completed: true,
current_offset: 0,
},
Chunk {
index: 1,
start: 11,
end: 20,
completed: false,
current_offset: 0,
},
],
};
save_state(&state, path_str).await?;
let content = tokio::fs::read_to_string(path_str).await?;
let loaded_state: DownloadState = serde_json::from_str(&content)?;
assert_eq!(loaded_state.url, "http://example.com");
assert_eq!(loaded_state.chunks.len(), 2);
assert!(loaded_state.chunks[0].completed);
assert!(!loaded_state.chunks[1].completed);
Ok(())
}
}