stormdl-segment 0.1.2

Segment manager with adaptive splitting algorithm
Documentation
use std::time::Duration;

#[derive(Debug, Clone, Copy)]
pub enum SplitStrategy {
    Static(usize),
    Adaptive,
}

pub fn optimal_segments(file_size: u64, measured_bw: f64, rtt: Duration) -> usize {
    let bdp = measured_bw * rtt.as_secs_f64();
    let tcp_window = 65536.0;
    let min_connections = (bdp / tcp_window).ceil() as usize;

    let max_connections = match file_size {
        0..=1_000_000 => 1,
        1_000_001..=10_000_000 => 4,
        10_000_001..=100_000_000 => 8,
        100_000_001..=1_000_000_000 => 16,
        _ => 32,
    };

    min_connections.clamp(1, max_connections)
}

pub fn initial_segments(file_size: u64) -> usize {
    match file_size {
        0..=1_000_000 => 1,
        1_000_001..=10_000_000 => 4,
        _ => 8,
    }
}

pub fn turbo_segments(file_size: u64) -> usize {
    match file_size {
        0..=1_000_000 => 1,
        1_000_001..=10_000_000 => 8,
        _ => 16,
    }
}

pub fn split_range(total_size: u64, num_segments: usize) -> Vec<stormdl_core::ByteRange> {
    if num_segments == 0 || total_size == 0 {
        return vec![];
    }

    let segment_size = total_size / num_segments as u64;
    let remainder = total_size % num_segments as u64;

    let mut ranges = Vec::with_capacity(num_segments);
    let mut offset = 0;

    for i in 0..num_segments {
        let extra = if i < remainder as usize { 1 } else { 0 };
        let size = segment_size + extra;
        ranges.push(stormdl_core::ByteRange::new(offset, offset + size));
        offset += size;
    }

    ranges
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_split_range_even() {
        let ranges = split_range(100, 4);
        assert_eq!(ranges.len(), 4);
        assert_eq!(ranges[0], stormdl_core::ByteRange::new(0, 25));
        assert_eq!(ranges[1], stormdl_core::ByteRange::new(25, 50));
        assert_eq!(ranges[2], stormdl_core::ByteRange::new(50, 75));
        assert_eq!(ranges[3], stormdl_core::ByteRange::new(75, 100));
    }

    #[test]
    fn test_split_range_uneven() {
        let ranges = split_range(10, 3);
        assert_eq!(ranges.len(), 3);
        assert_eq!(ranges[0].len() + ranges[1].len() + ranges[2].len(), 10);
    }
}