use std::collections::Bound;
use std::num::NonZeroUsize;
use std::ops::RangeBounds;
use std::sync::Arc;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone)]
pub struct RemainingChunks {
pub chunk_size: NonZeroUsize,
pub ranges: Vec<ChunkRange>,
}
#[allow(dead_code)]
enum ChunkHandle {
Update {
index: usize,
range: ChunkRange,
},
Split {
index: usize,
left: ChunkRange,
right: ChunkRange,
},
Remove {
index: usize,
},
Error,
}
impl RemainingChunks {
pub fn new(chunk_size: NonZeroUsize, total_len: u64) -> Self {
Self {
chunk_size,
ranges: vec![ChunkRange::from_len(0, total_len)],
}
}
pub fn take_first(&mut self) -> Option<ChunkRange> {
let chunk_size = self.chunk_size.get() as u64;
match self.ranges.first().map(|n| n.to_owned()) {
None => None,
Some(range) => {
let len = match range.len() {
0 => {
self.handle(ChunkHandle::Remove { index: 0 });
return self.take_first();
}
len if len <= chunk_size => {
self.handle(ChunkHandle::Remove { index: 0 });
len
}
_ => {
self.handle(ChunkHandle::Update {
index: 0,
range: ChunkRange::new(range.start + chunk_size, range.end),
});
chunk_size
}
};
Some(ChunkRange::from_len(range.start, len))
}
}
}
fn handle(&mut self, handle: ChunkHandle) -> bool {
match handle {
ChunkHandle::Update { index, range } => {
self.ranges[index] = range;
}
ChunkHandle::Split { index, left, right } => {
self.ranges[index] = right;
self.ranges.insert(index, left);
}
ChunkHandle::Remove { index } => {
self.ranges.remove(index);
}
ChunkHandle::Error => {
return false;
}
}
true
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone)]
pub struct ChunkData {
pub iter_count: usize,
pub remaining: RemainingChunks,
pub last_incomplete_chunks: Vec<ChunkInfo>,
}
impl ChunkData {
pub fn remaining_len(&self) -> u64 {
let mut len = 0;
for x in &self.remaining.ranges {
len += x.len();
}
for x in &self.last_incomplete_chunks {
len += x.range.len();
}
len
}
pub fn next_chunk_range(&mut self) -> Option<ChunkInfo> {
if let Some(chunk) = self.last_incomplete_chunks.pop() {
return Some(chunk);
}
let range = self.remaining.take_first();
if let Some(range) = range {
self.iter_count += 1;
let result = ChunkInfo {
index: self.iter_count,
range,
};
Some(result)
} else {
None
}
}
}
#[derive(Debug)]
pub struct ChunkIterator {
pub content_length: u64,
pub data: Arc<parking_lot::Mutex<ChunkData>>,
}
impl ChunkIterator {
pub fn new(content_length: u64, data: ChunkData) -> Self {
Self {
content_length,
data: Arc::new(parking_lot::Mutex::new(data)),
}
}
pub fn next(&self) -> Option<ChunkInfo> {
let mut data = self.data.lock();
data.next_chunk_range()
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone)]
pub struct ChunkInfo {
pub index: usize,
pub range: ChunkRange,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Copy, Clone)]
pub struct ChunkRange {
pub start: u64,
pub end: u64,
}
impl ChunkRange {
pub fn new(start: u64, end: u64) -> Self {
debug_assert!(end >= start, "start: {},end:{}", start, end);
Self {
start,
end,
}
}
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> u64 {
(self.end - self.start) + 1
}
pub fn to_range_header(&self) -> headers::Range {
headers::Range::bytes(self).unwrap()
}
pub fn from_len(start: u64, len: u64) -> Self {
Self {
start,
end: start + len - 1,
}
}
}
impl<'a> RangeBounds<u64> for &'a ChunkRange {
fn start_bound(&self) -> Bound<&u64> {
Bound::Included(&self.start)
}
fn end_bound(&self) -> Bound<&u64> {
Bound::Included(&self.end)
}
}