Bindings to the seekable variant of the ZSTD compression format
#[cfg(feature = "threadpool")]
use zstd_seekable::parallel_compress;
use zstd_seekable::{Seekable, SeekableCStream};

const DATA: &[u8; 731] = b"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut diam ante, sollicitudin a dolor et, volutpat elementum nulla. Etiam nec efficitur nibh, quis rutrum risus. Maecenas quis lorem malesuada, aliquet mi vel, viverra nunc. Donec et nulla sed velit sagittis varius. Suspendisse vestibulum, neque lobortis ornare vestibulum, orci turpis vulputate nisi, ut sodales neque purus eget magna. Nunc condimentum, diam eu consequat venenatis, est nisl semper lorem, et lobortis velit justo sed nulla. Nunc sit amet tempor nunc, vel posuere ipsum. Cras erat tortor, pulvinar ac pretium eu, auctor ac nibh. Duis iaculis porta magna, eu lobortis elit. Duis vitae massa eros. Nulla non magna accumsan, egestas quam sit amet, laoreet lectus.";

#[test]
#[cfg(feature = "threadpool")]
fn test_par_1() {
    let mut output = Vec::new();
    const CHUNK_SIZE: usize = 200;
    parallel_compress::<&mut Vec<u8>, [u8; CHUNK_SIZE]>(DATA, &mut output, 10, 4, CHUNK_SIZE)
        .unwrap();
    let mut decomp = Vec::new();
    let mut s = { Seekable::init_buf(&mut output[..]).unwrap() };

    for frame in 0..s.get_num_frames() {
        let size = s.get_frame_decompressed_size(frame).unwrap() as usize;
        let n = decomp.len();
        decomp.extend(std::iter::repeat(0).take(size));
        s.decompress_frame(&mut decomp[n..], frame).unwrap();
    }
    println!("{:?}", std::str::from_utf8(&decomp).unwrap());

    assert_eq!(&DATA[..], &decomp[..])
}

#[test]
#[cfg(feature = "threadpool")]
fn test_par_2() {
    let mut output = Vec::new();
    const CHUNK_SIZE: usize = 128;
    parallel_compress::<&mut Vec<u8>, [u8; CHUNK_SIZE]>(DATA, &mut output, 10, 4, CHUNK_SIZE)
        .unwrap();
    let b_size = 1024;
    let mut decomp = vec![0; b_size];
    let mut s = { Seekable::init_buf(output.as_mut_slice()).unwrap() };
    let mut start_offset = 0;
    let end_offset = DATA.len();
    let mut i = 0;

    while start_offset < end_offset {
        let dst_size = std::cmp::min(end_offset - start_offset, b_size);
        let r = s
            .decompress(
                &mut decomp[i * dst_size..i * dst_size + dst_size],
                start_offset as u64,
            )
            .unwrap();

        if r == 0 {
            break;
        }

        i += 1;
        start_offset += r;
    }
    decomp.truncate(end_offset);
    println!("{:?}", std::str::from_utf8(&decomp).unwrap());
    assert_eq!(&DATA[..], &decomp[..])
}

#[test]
#[cfg(feature = "threadpool")]
fn test_par_3() {
    let mut output = Vec::new();
    const CHUNK_SIZE: usize = 100;
    parallel_compress::<&mut Vec<u8>, [u8; CHUNK_SIZE]>(DATA, &mut output, 10, 4, CHUNK_SIZE)
        .unwrap();
    let b_size = 100;
    let mut decomp = vec![0; b_size];
    let mut s = { Seekable::init_buf(output.as_mut_slice()).unwrap() };
    let mut start_offset = 0;
    let end_offset = DATA.len();
    let mut i = 0;
    let mut string_stream = String::new(); // just to check the final value

    while start_offset < end_offset {
        let dst_size = std::cmp::min(end_offset - start_offset, b_size);
        let r = s
            .decompress(&mut decomp[..dst_size], start_offset as u64)
            .unwrap();

        string_stream.push_str(std::str::from_utf8(&decomp[..r]).unwrap());
        assert_eq!(&DATA[i * b_size..i * b_size + dst_size], &decomp[..r]);

        if r == 0 {
            break;
        }
        i += 1;
        start_offset += r;
    }

    print!("{:?}", string_stream);
}

#[test]
fn test() {
    let mut cstream = SeekableCStream::new(10, 256).unwrap();
    let mut input_pos = 0;
    let mut output = vec![0; DATA.len()];
    let mut output_pos = 0;
    while input_pos < DATA.len() {
        let (a, b) = cstream
            .compress(&mut output[output_pos..], &DATA[input_pos..])
            .unwrap();
        output_pos += a;
        input_pos += b;
    }
    while let Ok(n) = cstream.end_stream(&mut output[output_pos..]) {
        if n == 0 {
            break;
        }
        output_pos += n;
    }
    output.truncate(output_pos);
    {
        use std::io::Write;
        let mut file = std::fs::File::create("test").unwrap();
        file.write_all(&output).unwrap();
    }
    println!("data len = {:?}, pos = {:?}", DATA.len(), output_pos);

    let mut decomp = Vec::new();
    let mut s = { Seekable::init_buf(&output).unwrap() };
    for frame in 0..s.get_num_frames() {
        let size = s.get_frame_decompressed_size(frame).unwrap() as usize;
        let n = decomp.len();
        decomp.extend(std::iter::repeat(0).take(size));
        s.decompress_frame(&mut decomp[n..], frame).unwrap();
    }
    println!("{:?}", std::str::from_utf8(&decomp).unwrap());
    assert_eq!(&DATA[..], &decomp[..])
}