futures-byteorder 1.0.1

A modern async byteorder library for the smol/futures-lite ecosystem
Documentation
use std::{f32, f64};

use async_io::block_on;
use futures_lite::io::{self, Cursor};
use pastey::paste;

use super::*;

#[macro_use]
mod macros;
mod fuzz;

#[test]
fn test_read_u8() -> io::Result<()> {
    let mut data = Cursor::new([0x42]);
    let mut reader = AsyncReadBytes::new(&mut data);
    assert_eq!(block_on(reader.read_u8())?, 0x42);
    Ok(())
}

#[test]
fn test_read_i8() -> io::Result<()> {
    let mut data = Cursor::new([0xFF]);
    let mut reader = AsyncReadBytes::new(&mut data);
    assert_eq!(block_on(reader.read_i8())?, -1);
    Ok(())
}

#[test]
fn test_write_u8() -> io::Result<()> {
    let mut buf = Vec::new();
    let mut writer = AsyncWriteBytes::new(&mut buf);
    block_on(writer.write_u8(0x42))?;
    assert_eq!(buf, [0x42]);
    Ok(())
}

#[test]
fn test_write_i8() -> io::Result<()> {
    let mut buf = Vec::new();
    let mut writer = AsyncWriteBytes::new(&mut buf);
    block_on(writer.write_i8(-1))?;
    assert_eq!(buf, [0xFF]);
    Ok(())
}

#[test]
fn test_partial_read_error() {
    let mut data = Cursor::new([0x12]); // Only 1 byte
    let mut reader = AsyncReadBytes::new(&mut data);
    assert!(block_on(reader.read_u16::<BE>()).is_err());
}

#[test]
fn test_empty_read_error() {
    let mut data = Cursor::new([]);
    let mut reader = AsyncReadBytes::new(&mut data);
    assert!(block_on(reader.read_u8()).is_err());
}

#[test]
fn test_zero_values() -> io::Result<()> {
    let mut buf = Vec::new();
    let mut writer = AsyncWriteBytes::new(&mut buf);
    block_on(writer.write_u64::<BE>(0))?;
    assert_eq!(buf, [0, 0, 0, 0, 0, 0, 0, 0]);
    Ok(())
}

#[test]
fn test_max_values() -> io::Result<()> {
    let mut buf = Vec::new();
    let mut writer = AsyncWriteBytes::new(&mut buf);

    block_on(writer.write_u8(u8::MAX))?;
    block_on(writer.write_u16::<BE>(u16::MAX))?;
    block_on(writer.write_u32::<BE>(u32::MAX))?;
    block_on(writer.write_u64::<BE>(u64::MAX))?;

    assert_eq!(
        buf,
        [
            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
            0xFF,
        ]
    );
    Ok(())
}

#[test]
fn test_min_signed_values() -> io::Result<()> {
    let mut buf = Vec::new();
    let mut writer = AsyncWriteBytes::new(&mut buf);

    block_on(writer.write_i8(i8::MIN))?;
    block_on(writer.write_i16::<BE>(i16::MIN))?;
    block_on(writer.write_i32::<BE>(i32::MIN))?;

    assert_eq!(buf, [0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00,]);
    Ok(())
}

#[test]
fn test_sequential_operations() -> io::Result<()> {
    let mut buf = Vec::new();
    let mut writer = AsyncWriteBytes::new(&mut buf);

    // Write multiple values in sequence
    block_on(writer.write_u8(0x12))?;
    block_on(writer.write_u16::<BE>(0x3456))?;
    block_on(writer.write_u32::<LE>(0x789A_BCDE))?;

    // Read them back
    let mut reader = Cursor::new(&buf);
    let mut reader = AsyncReadBytes::new(&mut reader);

    assert_eq!(block_on(reader.read_u8())?, 0x12);
    assert_eq!(block_on(reader.read_u16::<BE>())?, 0x3456);
    assert_eq!(block_on(reader.read_u32::<LE>())?, 0x789A_BCDE);
    Ok(())
}

#[test]
fn test_special_floats() -> io::Result<()> {
    let mut buf = Vec::new();
    let mut writer = AsyncWriteBytes::new(&mut buf);

    // Test special float values
    block_on(writer.write_f32::<BE>(0.0))?;
    block_on(writer.write_f32::<BE>(-0.0))?;
    block_on(writer.write_f32::<BE>(f32::INFINITY))?;
    block_on(writer.write_f32::<BE>(f32::NEG_INFINITY))?;

    let mut reader = Cursor::new(&buf);
    let mut reader = AsyncReadBytes::new(&mut reader);

    assert_eq!(
        block_on(reader.read_f32::<BE>())?.to_bits(),
        0.0f32.to_bits()
    );
    assert_eq!(
        block_on(reader.read_f32::<BE>())?.to_bits(),
        (-0.0f32).to_bits()
    );
    assert!(block_on(reader.read_f32::<BE>())?.is_infinite());
    assert!(block_on(reader.read_f32::<BE>())?.is_infinite());
    Ok(())
}

#[test]
fn test_nan_roundtrip() -> io::Result<()> {
    let mut buf = Vec::new();
    let mut writer = AsyncWriteBytes::new(&mut buf);
    block_on(writer.write_f32::<BE>(f32::NAN))?;

    let mut reader = Cursor::new(&buf);
    let mut reader = AsyncReadBytes::new(&mut reader);
    assert!(block_on(reader.read_f32::<BE>())?.is_nan());
    Ok(())
}

// Deref/DerefMut tests
#[test]
fn test_reader_deref() {
    let data = vec![0x12, 0x34, 0x56, 0x78];
    let mut cursor = Cursor::new(data);
    let reader = AsyncReadBytes::new(&mut cursor);

    // Should be able to use cursor methods through deref
    assert_eq!(reader.position(), 0);
}

#[test]
fn test_writer_deref() {
    let mut buf = Vec::new();
    let mut cursor = Cursor::new(&mut buf);
    let writer = AsyncWriteBytes::new(&mut cursor);

    // Should be able to use cursor methods through deref
    assert_eq!(writer.position(), 0);
}

// From trait tests
#[test]
fn test_reader_from() -> io::Result<()> {
    let mut data = Cursor::new([0x12, 0x34]);
    let mut reader: AsyncReadBytes<_> = (&mut data).into();
    assert_eq!(block_on(reader.read_u16::<BE>())?, 0x1234);
    Ok(())
}

#[test]
fn test_writer_from() -> io::Result<()> {
    let mut buf = Vec::new();
    let mut writer: AsyncWriteBytes<_> = (&mut buf).into();
    block_on(writer.write_u16::<BE>(0x1234))?;
    assert_eq!(buf, [0x12, 0x34]);
    Ok(())
}

integer_tests! {
    u16: {
        value: 0x1234,
        be_bytes: [0x12, 0x34],
        le_bytes: [0x34, 0x12],
    },
    i16: {
        value: -1,
        be_bytes: [0xFF, 0xFF],
        le_bytes: [0xFF, 0xFF],
    },
    u32: {
        value: 0x1234_5678,
        be_bytes: [0x12, 0x34, 0x56, 0x78],
        le_bytes: [0x78, 0x56, 0x34, 0x12],
    },
    i32: {
        value: -1,
        be_bytes: [0xFF, 0xFF, 0xFF, 0xFF],
        le_bytes: [0xFF, 0xFF, 0xFF, 0xFF],
    },
    u64: {
        value: 0x1234_5678_9ABC_DEF0,
        be_bytes: [0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0],
        le_bytes: [0xF0, 0xDE, 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12],
    },
    i64: {
        value: -1,
        be_bytes: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
        le_bytes: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
    },
    u128: {
        value: 0x0123_4567_89AB_CDEF_FEDC_BA98_7654_3210,
        be_bytes: [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
                   0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10],
        le_bytes: [0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
                   0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01],
    },
    i128: {
        value: -1,
        be_bytes: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
        le_bytes: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
    },
}

float_tests! {
    f32: {
        value: f32::consts::PI,
        be_bytes: f32::consts::PI.to_be_bytes(),
        le_bytes: f32::consts::PI.to_le_bytes(),
    },
    f64: {
        value: f64::consts::PI,
        be_bytes: f64::consts::PI.to_be_bytes(),
        le_bytes: f64::consts::PI.to_le_bytes(),
    },
}