async-read-util 0.2.0

A collection of utilities for working with AsyncRead.
Documentation
use async_read_util::AsyncReadUtil;
use futures::{io::Cursor, AsyncReadExt};
use rand::{thread_rng, Fill};
use std::cmp::min;

#[smol_potat::test]
async fn test_observe() {
    let mut rng = thread_rng();
    let mut source = [0u8; 4096];
    source.try_fill(&mut rng).expect("fill with random numbers");
    let reader = Cursor::new(source);
    let mut copied = vec![];
    let mut observed = reader.observe(|chunk| copied.extend_from_slice(chunk));
    let mut collected = vec![];
    let mut buf = [0u8; 1024];
    loop {
        let nread = observed.read(&mut buf[..]).await.expect("able to read");
        if nread == 0 {
            break;
        }
        collected.extend_from_slice(&buf[..nread]);
    }
    assert_eq!(collected, copied);
}

#[smol_potat::test]
async fn test_map() {
    let mut rng = thread_rng();
    let mut source = [0u8; 4096];
    source.try_fill(&mut rng).expect("fill with random numbers");
    let reader = Cursor::new(source);

    let mut mapped_reader = reader.map_read(|src, dst| {
        for (x, y) in src.iter().zip(dst.iter_mut()) {
            *y = x / 2;
        }
        let nread = min(dst.len(), src.len());
        (nread, nread)
    });

    let mut collected = vec![];
    let mut buf = [0u8; 1024];
    loop {
        let nread = mapped_reader
            .read(&mut buf[..])
            .await
            .expect("able to read");
        if nread == 0 {
            break;
        }
        collected.extend_from_slice(&buf[..nread]);
    }
    assert_eq!(collected, source.iter().map(|x| x / 2).collect::<Vec<u8>>());
}

#[smol_potat::test]
async fn test_map_expanding() {
    let mut rng = thread_rng();
    let mut source = [0u8; 4096];
    source.try_fill(&mut rng).expect("fill with random numbers");
    let reader = Cursor::new(source);

    let mut mapped_reader = reader.map_read(|src, dst| {
        let mut nread = 0;
        for (x, ys) in src.iter().zip(dst.chunks_mut(2)) {
            for y in ys {
                *y = *x;
            }
            nread += 1;
        }
        (nread, nread * 2)
    });

    let mut collected = vec![];
    let mut buf = [0u8; 1024];
    loop {
        let nread = mapped_reader
            .read(&mut buf[..])
            .await
            .expect("able to read");
        if nread == 0 {
            break;
        }
        collected.extend_from_slice(&buf[..nread]);
    }
    assert_eq!(
        collected,
        source
            .iter()
            .flat_map(|x| vec![*x, *x])
            .collect::<Vec<u8>>()
    );
}

#[smol_potat::test]
async fn test_map_contracting() {
    let mut rng = thread_rng();
    let mut source = [0u8; 4096];
    source.try_fill(&mut rng).expect("fill with random numbers");
    let reader = Cursor::new(source);

    let mut mapped_reader = reader.map_read(|src, dst| {
        let mut nread = 0;
        for (xs, y) in src.chunks(2).zip(dst) {
            *y = *xs.iter().min().unwrap();
            nread += 1;
        }
        (nread * 2, nread)
    });

    let mut collected = vec![];
    let mut buf = [0u8; 1024];
    loop {
        let nread = mapped_reader
            .read(&mut buf[..])
            .await
            .expect("able to read");
        if nread == 0 {
            break;
        }
        collected.extend_from_slice(&buf[..nread]);
    }
    assert_eq!(
        collected,
        source
            .chunks(2)
            .map(|xs| *xs.iter().min().unwrap())
            .collect::<Vec<u8>>()
    );
}