use jvmrs::compressed_oops::{CompressedOops, OopMode};
use jvmrs::MemoryError;
struct PackedRefArray {
oops: CompressedOops,
slots: Vec<u16>,
}
impl PackedRefArray {
fn new(oops: CompressedOops, capacity: usize) -> Self {
Self {
oops,
slots: Vec::with_capacity(capacity),
}
}
fn push(&mut self, handle: u32) -> Result<(), MemoryError> {
self.slots.push(self.oops.encode(handle)?);
Ok(())
}
fn get(&self, index: usize) -> u32 {
self.oops.decode(self.slots[index])
}
fn len(&self) -> usize {
self.slots.len()
}
fn storage_bytes(&self) -> usize {
self.slots.len() * 2
}
}
#[test]
fn test_packed_ref_array_round_trip() {
let oops = CompressedOops::compressed();
let mut arr = PackedRefArray::new(oops, 8);
for handle in 1..=8u32 {
arr.push(handle).unwrap();
}
assert_eq!(arr.len(), 8);
for (i, expected) in (1..=8u32).enumerate() {
assert_eq!(arr.get(i), expected);
}
}
#[test]
fn test_packed_ref_array_saves_memory() {
let oops = CompressedOops::compressed();
let mut arr = PackedRefArray::new(oops, 1000);
for handle in 0..1000u32 {
arr.push(handle).unwrap();
}
assert_eq!(arr.storage_bytes(), 2000);
let savings = oops.savings(1000);
assert_eq!(savings, 2000);
assert_eq!(savings as f64 / 4000.0, 0.5);
}
#[test]
fn test_overflow_rejects_invalid_handle() {
let oops = CompressedOops::compressed();
let mut arr = PackedRefArray::new(oops, 4);
arr.push(65535).unwrap();
assert!(matches!(
arr.push(65536),
Err(MemoryError::CompressedOopsOverflow(65536))
));
assert_eq!(arr.len(), 1); }
#[test]
fn test_mode_switch_changes_capacity() {
let standard = CompressedOops::standard();
let compressed = CompressedOops::compressed();
assert_eq!(standard.max_handle(), u32::MAX);
assert_eq!(compressed.max_handle(), 65535);
assert!(standard.encode(0xFFFF_FFFF).is_ok());
assert!(compressed.encode(0xFFFF_FFFF).is_err());
}
#[test]
fn test_aligned_compression_with_shift() {
let oops = CompressedOops::compressed_with(0, 3);
assert_eq!(oops.max_handle(), 0xFFFF * 8);
let mut arr = PackedRefArray::new(oops, 4);
let aligned_handles = [0u32, 8, 16, 24];
for &h in &aligned_handles {
arr.push(h).unwrap();
}
for (i, &expected) in aligned_handles.iter().enumerate() {
assert_eq!(arr.get(i), expected);
}
}
#[test]
fn test_bulk_decode_after_encode() {
let oops = CompressedOops::compressed();
let original: Vec<u32> = (0..=65535u32).step_by(257).collect();
let encoded = oops.encode_slice(&original).unwrap();
let decoded = oops.decode_slice(&encoded);
assert_eq!(decoded, original);
assert_eq!(encoded.iter().map(|v| *v as usize).sum::<usize>() > 0, true);
}
#[test]
fn test_default_is_standard() {
let oops = CompressedOops::default();
assert_eq!(oops.mode, OopMode::Standard);
assert!(!oops.is_compressed());
}
#[test]
fn test_compressed_mode_predicate() {
let standard = CompressedOops::standard();
let compressed = CompressedOops::compressed();
let with_shift = CompressedOops::compressed_with(0x1000, 2);
assert!(!standard.is_compressed());
assert!(compressed.is_compressed());
assert!(with_shift.is_compressed());
}
#[test]
fn test_compressed_field_map_simulation() {
let oops = CompressedOops::compressed();
let fields = ["next", "prev", "parent", "child"];
let raw_values = [10u32, 11, 12, 13];
let packed: Vec<((&str, u16))> = fields
.iter()
.zip(raw_values.iter())
.map(|(k, &v)| (*k, oops.encode(v).unwrap()))
.collect();
for (i, (_, encoded)) in packed.iter().enumerate() {
assert_eq!(oops.decode(*encoded), raw_values[i]);
}
}
#[test]
fn test_compressed_savings_zero_in_standard_mode() {
let oops = CompressedOops::standard();
assert_eq!(oops.savings_per_slot(), 0);
assert_eq!(oops.savings(100_000), 0);
}