use std::path::PathBuf; #[derive(Debug, Clone)] pub struct FileInfo { pub relative_filename: PathBuf, pub offset_in_torrent: u64, pub piece_range: std::ops::Range, pub len: u64, } // Iterate file pieces in the following order: first, last, everything else from start to end. fn iter_piece_priorities(range: std::ops::Range) -> impl Iterator { // First and last of each file first, then the rest of pieces in that file. let r = range; use std::iter::once; let first = once(r.start); let last = once(r.start + r.len().overflowing_sub(1).0); // it's ok if it repeats, doesn't matter let mid = r.clone().skip(1).take(r.len().overflowing_sub(2).0); // The take(r.len()) is to not yield start/end pieces in case of 0 and 1 lengths. first.chain(last).chain(mid).take(r.len()) } impl FileInfo { pub fn piece_range_usize(&self) -> std::ops::Range { self.piece_range.start as usize..self.piece_range.end as usize } pub fn iter_piece_priorities(&self) -> impl Iterator { iter_piece_priorities(self.piece_range_usize()) } } #[cfg(test)] mod tests { use super::iter_piece_priorities; #[test] fn test_iter_piece_priorities() { let it = |r: std::ops::Range| -> Vec { iter_piece_priorities(r).collect() }; assert_eq!(it(0..0), Vec::::new()); assert_eq!(it(0..1), vec![0]); assert_eq!(it(0..2), vec![0, 1]); assert_eq!(it(0..3), vec![0, 2, 1]); assert_eq!(it(0..4), vec![0, 3, 1, 2]); } }