1
0
Fork 0
mirror of https://codeberg.org/icewind/bitbuffer.git synced 2026-06-04 00:54:07 +02:00
bitbuffer/bitbuffer_derive/tests/read.rs
Nikita Strygin e33aa2f776 Add #[align] attribute to structs
This attribute aligns the reader to byte boundary

It can be applied to enums & structs to align before reading any fields or the discriminant

It can also be applied to individual struct fields to align the reader before reading the field

Finally, you can apply it to non-unit enum variants to align the reader after reading the discriminant, but before reading the payload
2023-02-06 15:49:33 +03:00

413 lines
10 KiB
Rust

#![allow(dead_code)]
#![allow(unreachable_patterns)]
use bitbuffer::{
bit_size_of, bit_size_of_sized, BigEndian, BitReadBuffer, BitReadStream, Endianness,
LittleEndian,
};
use bitbuffer_derive::{BitRead, BitReadSized};
#[derive(BitRead, PartialEq, Debug)]
struct TestStruct {
foo: u8,
str: String,
#[size = 2]
truncated: String,
bar: u16,
float: f32,
#[size = 3]
asd: u8,
#[size_bits = 2]
dynamic: u8,
#[size = "asd"]
previous_field: u8,
}
#[test]
fn test_read_struct() {
let float: [u8; 4] = 12.5f32.to_bits().to_le_bytes();
let bytes = vec![
12,
'h' as u8,
'e' as u8,
'l' as u8,
'l' as u8,
'o' as u8,
0,
'f' as u8,
'o' as u8,
'o' as u8,
0,
float[0],
float[1],
float[2],
float[3],
0b0101_0101,
0b1010_1010,
];
let buffer = BitReadBuffer::new(&bytes, LittleEndian);
let mut stream = BitReadStream::from(buffer);
assert_eq!(
TestStruct {
foo: 12,
str: "hello".to_owned(),
truncated: "fo".to_owned(),
bar: 'o' as u16,
float: 12.5,
asd: 0b101,
dynamic: 0b10,
previous_field: 0b1010_0,
},
stream.read().unwrap()
);
assert_eq!(None, bit_size_of::<TestStruct>());
}
#[derive(BitRead, PartialEq, Debug)]
#[discriminant_bits = 2]
enum TestBareEnum {
Foo,
Bar,
Asd = 3,
}
#[test]
fn test_read_bare_enum() {
let bytes = vec![
0b1100_0110,
0b1000_0100,
0b1000_0100,
0b1000_0100,
0b1000_0100,
0b1000_0100,
0b1000_0100,
0b1000_0100,
];
let buffer = BitReadBuffer::new(&bytes, BigEndian);
let mut stream = BitReadStream::from(buffer);
assert_eq!(TestBareEnum::Asd, stream.read().unwrap());
assert_eq!(TestBareEnum::Foo, stream.read().unwrap());
assert_eq!(TestBareEnum::Bar, stream.read().unwrap());
assert_eq!(true, stream.read::<TestBareEnum>().is_err());
assert_eq!(Some(2), bit_size_of::<TestBareEnum>());
}
#[derive(BitRead, PartialEq, Debug)]
#[discriminant_bits = 2]
enum TestUnnamedFieldEnum {
#[size = 5]
Foo(i8),
Bar(bool),
#[discriminant = 3]
Asd(u8),
}
#[test]
fn test_read_unnamed_field_enum() {
let bytes = vec![
0b1100_0110,
0b1000_0100,
0b1000_0100,
0b1000_0100,
0b1000_0100,
0b1000_0100,
0b1000_0100,
0b1000_0100,
];
let buffer = BitReadBuffer::new(&bytes, BigEndian);
let mut stream = BitReadStream::from(buffer);
assert_eq!(
TestUnnamedFieldEnum::Asd(0b_00_0110_10),
stream.read().unwrap()
);
assert_eq!(10, stream.pos());
stream.set_pos(2).unwrap();
assert_eq!(TestUnnamedFieldEnum::Foo(0b11_0_1), stream.read().unwrap());
assert_eq!(9, stream.pos());
stream.set_pos(4).unwrap();
assert_eq!(TestUnnamedFieldEnum::Bar(true), stream.read().unwrap());
assert_eq!(7, stream.pos());
assert_eq!(None, bit_size_of::<TestUnnamedFieldEnum>());
}
#[derive(BitReadSized, PartialEq, Debug)]
struct TestStructSized {
foo: u8,
#[size = "input_size"]
string: String,
#[size = "input_size"]
int: u8,
}
#[test]
fn test_read_struct_sized() {
let bytes = vec![
12, 'h' as u8, 'e' as u8, 'l' as u8, 'l' as u8, 'o' as u8, 0, 0, 0, 0, 0, 0,
];
let buffer = BitReadBuffer::new(&bytes, LittleEndian);
let mut stream = BitReadStream::from(buffer);
assert_eq!(
TestStructSized {
foo: 12,
string: "hel".to_owned(),
int: 4,
},
stream.read_sized(3).unwrap()
);
assert_eq!(Some(8 + 2 * 8 + 2), bit_size_of_sized::<TestStructSized>(2));
}
#[derive(BitReadSized, PartialEq, Debug)]
#[discriminant_bits = 2]
enum TestUnnamedFieldEnumSized {
#[size = 5]
Foo(i8),
Bar(bool),
#[discriminant = 3]
#[size = "input_size"]
Asd(u8),
}
#[test]
fn test_read_unnamed_field_enum_sized() {
let bytes = vec![
0b1100_0110,
0b1000_0100,
0b1000_0100,
0b1000_0100,
0b1000_0100,
0b1000_0100,
0b1000_0100,
0b1000_0100,
];
let buffer = BitReadBuffer::new(&bytes, BigEndian);
let mut stream = BitReadStream::from(buffer);
assert_eq!(
TestUnnamedFieldEnumSized::Asd(0b_00_0110),
stream.read_sized(6).unwrap()
);
assert_eq!(8, stream.pos());
assert_eq!(None, bit_size_of_sized::<TestUnnamedFieldEnumSized>(6));
}
#[derive(BitRead, PartialEq, Debug)]
struct TestStruct2 {
size: u8,
#[size = "size * 2"]
str: String,
}
#[test]
fn test_read_struct2() {
let bytes = vec![
0b0000_0101,
'h' as u8,
'e' as u8,
'l' as u8,
'l' as u8,
'o' as u8,
' ' as u8,
'w' as u8,
'o' as u8,
'r' as u8,
'l' as u8,
'e' as u8,
];
let buffer = BitReadBuffer::new(&bytes, BigEndian);
let mut stream = BitReadStream::from(buffer);
assert_eq!(
TestStruct2 {
size: 5,
str: "hello worl".to_owned(),
},
stream.read().unwrap()
);
assert_eq!(None, bit_size_of::<TestStruct2>());
}
#[derive(BitRead)]
#[endianness = "E"]
struct TestStruct3<'a, E: Endianness> {
size: u8,
#[size = "size"]
stream: BitReadStream<'a, E>,
}
#[test]
fn test_read_struct3() {
let bytes = vec![0b0000_0101, 0, 0, 0, 0, 0, 0, 0];
let buffer = BitReadBuffer::new(&bytes, BigEndian);
let mut stream = BitReadStream::from(buffer);
let result: TestStruct3<BigEndian> = stream.read().unwrap();
assert_eq!(5, result.size);
assert_eq!(5, result.stream.bit_len());
assert_eq!(None, bit_size_of::<TestStruct3<LittleEndian>>());
}
#[derive(BitRead, PartialEq, Debug)]
#[discriminant_bits = 2]
enum TestEnumRest {
Foo,
Bar,
#[discriminant = "_"]
Asd,
}
#[test]
fn test_read_rest_enum() {
let bytes = vec![
0b1100_0110,
0b1000_0100,
0b1000_0100,
0b1000_0100,
0b1000_0100,
0b1000_0100,
0b1000_0100,
0b1000_0100,
];
let buffer = BitReadBuffer::new(&bytes, BigEndian);
let mut stream = BitReadStream::from(buffer);
assert_eq!(TestEnumRest::Asd, stream.read().unwrap());
assert_eq!(TestEnumRest::Foo, stream.read().unwrap());
assert_eq!(TestEnumRest::Bar, stream.read().unwrap());
assert_eq!(TestEnumRest::Asd, stream.read().unwrap());
assert_eq!(Some(2), bit_size_of::<TestEnumRest>());
}
#[derive(BitRead, PartialEq, Debug)]
struct UnnamedSize(u8, #[size = 5] String, bool);
fn test_unnamed_struct() {
let bytes = vec![
12, 'h' as u8, 'e' as u8, 'l' as u8, 'l' as u8, 'o' as u8, 0, 0, 0, 0, 0, 0,
];
let buffer = BitReadBuffer::new(&bytes, LittleEndian);
let mut stream = BitReadStream::from(buffer);
assert_eq!(
UnnamedSize(12, "hello".to_string(), false),
stream.read().unwrap()
);
}
#[derive(BitRead, PartialEq, Debug)]
struct EmptyStruct;
fn test_empty_struct() {
let bytes = vec![0, 0, 0, 0];
let buffer = BitReadBuffer::new(&bytes, BigEndian);
let mut stream = BitReadStream::from(buffer);
assert_eq!(EmptyStruct, stream.read().unwrap());
assert_eq!(0, stream.pos());
assert_eq!(Some(0), bit_size_of::<EmptyStruct>());
}
#[derive(BitRead)]
struct SizeStruct {
foo: u8,
#[size = 6]
str: String,
bar: bool,
}
#[derive(BitRead)]
struct UnnamedSizeStruct(u8, #[size = 6] String, bool);
#[test]
fn test_bit_size() {
assert_eq!(bit_size_of::<SizeStruct>(), Some(8 + 8 * 6 + 1));
assert_eq!(bit_size_of::<UnnamedSizeStruct>(), Some(8 + 8 * 6 + 1));
}
#[derive(BitReadSized)]
struct SizeStructSized {
foo: u8,
#[size = "input_size"]
str: String,
bar: bool,
}
#[test]
fn test_bit_size_sized() {
assert_eq!(bit_size_of_sized::<SizeStructSized>(6), Some(8 + 8 * 6 + 1));
assert_eq!(
bit_size_of_sized::<SizeStructSized>(16),
Some(8 + 8 * 16 + 1)
);
}
#[derive(BitRead, PartialEq, Debug)]
#[align]
struct AlignStruct(u8);
#[test]
fn test_align() {
let bytes = vec![0, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
let buffer = BitReadBuffer::new(&bytes, BigEndian);
let mut stream = BitReadStream::from(buffer);
stream.read_bool().unwrap();
assert_eq!(AlignStruct(0x80), stream.read().unwrap());
assert_eq!(16, stream.pos());
assert_eq!(None, bit_size_of::<AlignStruct>());
}
#[derive(BitRead, PartialEq, Debug)]
#[align]
struct AlignFieldStruct {
#[size = 1]
foo: u8,
#[align]
bar: u8,
}
#[test]
fn test_align_field() {
let bytes = vec![0, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
let buffer = BitReadBuffer::new(&bytes, BigEndian);
let mut stream = BitReadStream::from(buffer);
assert_eq!(
AlignFieldStruct { foo: 0, bar: 0x80 },
stream.read().unwrap()
);
assert_eq!(16, stream.pos());
assert_eq!(None, bit_size_of::<AlignStruct>());
}
#[derive(BitRead, PartialEq, Debug)]
#[discriminant_bits = 4]
#[align]
enum AlignEnum {
Foo,
Bar(u8),
}
#[test]
fn test_align_enum() {
let bytes = vec![0x00, 0x18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
let buffer = BitReadBuffer::new(&bytes, BigEndian);
let mut stream = BitReadStream::from(buffer);
stream.read_bool().unwrap();
assert_eq!(AlignEnum::Bar(0x80), stream.read().unwrap());
assert_eq!(20, stream.pos());
assert_eq!(None, bit_size_of::<AlignEnum>());
}
#[derive(BitRead, PartialEq, Debug)]
#[discriminant_bits = 4]
#[align]
enum AlignEnumField {
Foo,
#[align]
Bar(u8),
}
#[test]
fn test_align_enum_field() {
let bytes = vec![0x00, 0x10, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
let buffer = BitReadBuffer::new(&bytes, BigEndian);
let mut stream = BitReadStream::from(buffer);
stream.read_bool().unwrap();
assert_eq!(AlignEnumField::Bar(0x80), stream.read().unwrap());
assert_eq!(24, stream.pos());
assert_eq!(None, bit_size_of::<AlignEnum>());
}