use bitcraft::{bitenum, bitstruct, bytestruct, byteval};
use std::hint::black_box;
use std::time::Instant;
bitenum! {
pub enum PerfState(2) {
IDLE = 0,
RUNNING = 1,
BLOCKED = 2,
}
}
#[derive(Default)]
struct StandardDescriptor {
pub is_privileged: bool,
pub priority: u8,
pub memory_pages: u16,
pub state: u8, }
bitstruct! {
pub struct PackedDescriptor(u16) {
pub is_privileged: bool = 1,
pub priority: u8 = 3,
pub memory_pages: u16 = 10,
pub state: PerfState = 2,
}
}
bytestruct! {
pub struct ArrayDescriptor(2) {
pub is_privileged: bool = 1, pub priority: u8 = 3, pub memory_pages: u16 = 10, pub state: PerfState = 2, }
}
byteval! {
pub struct PackedId24(3);
}
#[derive(Default)]
struct StandardId24([u8; 3]);
impl StandardId24 {
#[inline(always)]
fn set(&mut self, val: u32) {
let bytes = val.to_le_bytes();
self.0[0] = bytes[0];
self.0[1] = bytes[1];
self.0[2] = bytes[2];
}
#[inline(always)]
fn get(&self) -> u32 {
u32::from_le_bytes([self.0[0], self.0[1], self.0[2], 0])
}
}
#[cfg(debug_assertions)]
const ITERATIONS: u64 = 1_000_000; #[cfg(not(debug_assertions))]
const ITERATIONS: u64 = 1_000_000_000;
#[test]
#[allow(clippy::manual_is_multiple_of)]
fn test_comprehensive_performance() {
println!(
"\n=== Running Comprehensive Performance Comparison ({} iterations) ===",
ITERATIONS
);
println!("\n--- Part A: Complex Descriptors (4 fields, 16 bits total) ---");
let mut standard = StandardDescriptor::default();
let start_std = Instant::now();
for i in 0..ITERATIONS {
let val = (i % 1024) as u16;
standard.is_privileged = val % 2 == 0;
standard.priority = (val % 8) as u8;
standard.memory_pages = val;
standard.state = (val % 3) as u8;
black_box(&mut standard);
black_box(standard.is_privileged);
black_box(standard.priority);
black_box(standard.memory_pages);
black_box(standard.state);
}
let dur_std = start_std.elapsed();
println!("Standard Struct Time: {:?}", dur_std);
let mut packed = PackedDescriptor::default();
let start_packed = Instant::now();
for i in 0..ITERATIONS {
let val = (i % 1024) as u16;
packed.set_is_privileged(val % 2 == 0);
packed.set_priority((val % 8) as u8);
packed.set_memory_pages(val);
packed.set_state(PerfState::from_bits((val % 3) as u8));
black_box(&mut packed);
black_box(packed.is_privileged());
black_box(packed.priority());
black_box(packed.memory_pages());
black_box(packed.state());
}
let dur_packed = start_packed.elapsed();
println!("bitstruct! (u16) Time: {:?}", dur_packed);
let mut array = ArrayDescriptor::default();
let start_array = Instant::now();
for i in 0..ITERATIONS {
let val = (i % 1024) as u16;
array.set_is_privileged(val % 2 == 0);
array.set_priority((val % 8) as u8);
array.set_memory_pages(val);
array.set_state(PerfState::from_bits((val % 3) as u8));
black_box(&mut array);
black_box(array.is_privileged());
black_box(array.priority());
black_box(array.memory_pages());
black_box(array.state());
}
let dur_array = start_array.elapsed();
println!("bytestruct! ([u8; 2]) Time: {:?}", dur_array);
println!(
" -> bitstruct! Overhead: {:.2}x",
dur_packed.as_nanos() as f64 / dur_std.as_nanos() as f64
);
println!(
" -> bytestruct! Overhead: {:.2}x",
dur_array.as_nanos() as f64 / dur_std.as_nanos() as f64
);
println!("\n--- Part B: 24-bit Odd-Width IDs ([u8; 3]) ---");
let mut std_id = StandardId24::default();
let start_std_id = Instant::now();
for i in 0..ITERATIONS {
let val = (i % 0xFFFFFF) as u32;
std_id.set(val);
black_box(&mut std_id);
black_box(std_id.get());
}
let dur_std_id = start_std_id.elapsed();
println!("Standard Manual byte-ops Time: {:?}", dur_std_id);
let mut byteval_id;
let start_byteval_id = Instant::now();
for i in 0..ITERATIONS {
let val = (i % 0xFFFFFF) as u32;
byteval_id = PackedId24::from_u32(val);
black_box(&mut byteval_id);
black_box(byteval_id.to_u32());
}
let dur_byteval_id = start_byteval_id.elapsed();
println!("byteval! Time: {:?}", dur_byteval_id);
println!(
" -> byteval! Overhead: {:.2}x",
dur_byteval_id.as_nanos() as f64 / dur_std_id.as_nanos() as f64
);
println!("\n--- Part C: Enum Comparisons (bitenum vs std enum) ---");
#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(u8)]
enum StdEnum {
A = 0,
B = 1,
C = 2,
D = 3,
E = 4,
F = 5,
G = 6,
H = 7,
}
impl From<u8> for StdEnum {
#[inline(always)]
fn from(v: u8) -> Self {
match v % 8 {
0 => StdEnum::A,
1 => StdEnum::B,
2 => StdEnum::C,
3 => StdEnum::D,
4 => StdEnum::E,
5 => StdEnum::F,
6 => StdEnum::G,
_ => StdEnum::H,
}
}
}
bitenum! {
pub enum BitEnum(3) { A=0, B=1, C=2, D=3, E=4, F=5, G=6, H=7 }
}
let start_std_enum = Instant::now();
for i in 0..ITERATIONS {
let val = (i % 8) as u8;
let e = StdEnum::from(val);
let back = match e {
StdEnum::A => 0,
StdEnum::B => 1,
StdEnum::C => 2,
StdEnum::D => 3,
StdEnum::E => 4,
StdEnum::F => 5,
StdEnum::G => 6,
StdEnum::H => 7,
};
black_box(e);
black_box(back);
}
let dur_std_enum = start_std_enum.elapsed();
println!("Standard Enum Time: {:?}", dur_std_enum);
let start_bit_enum = Instant::now();
for i in 0..ITERATIONS {
let val = (i % 8) as u8;
let e = BitEnum::from_bits(val);
let back = match e.to_bits() {
0 => 0,
1 => 1,
2 => 2,
3 => 3,
4 => 4,
5 => 5,
6 => 6,
7 => 7,
_ => 0,
};
black_box(e);
black_box(back);
}
let dur_bit_enum = start_bit_enum.elapsed();
println!("bitenum! Time: {:?}", dur_bit_enum);
println!(
" -> bitenum! Overhead: {:.2}x",
dur_bit_enum.as_nanos() as f64 / dur_std_enum.as_nanos() as f64
);
}