#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum GcColor {
White = 0,
Gray = 1,
Black = 2,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Generation {
Young = 0,
Old = 1,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct GcHeader {
flags: u8,
pub kind: u8,
_reserved: u16,
pub size: u32,
}
impl GcHeader {
pub fn new(kind: u8, size: u32) -> Self {
Self {
flags: 0, kind,
_reserved: 0,
size,
}
}
#[inline(always)]
pub fn color(&self) -> GcColor {
match self.flags & 0b11 {
0 => GcColor::White,
1 => GcColor::Gray,
2 => GcColor::Black,
_ => GcColor::White, }
}
#[inline(always)]
pub fn set_color(&mut self, color: GcColor) {
self.flags = (self.flags & !0b11) | (color as u8);
}
#[inline(always)]
pub fn generation(&self) -> Generation {
if (self.flags >> 2) & 1 == 0 {
Generation::Young
} else {
Generation::Old
}
}
#[inline(always)]
pub fn set_generation(&mut self, generation: Generation) {
self.flags = (self.flags & !0b100) | ((generation as u8) << 2);
}
#[inline(always)]
pub fn is_forwarded(&self) -> bool {
(self.flags >> 3) & 1 != 0
}
#[inline(always)]
pub fn set_forwarded(&mut self, forwarded: bool) {
if forwarded {
self.flags |= 0b1000;
} else {
self.flags &= !0b1000;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_header_size() {
assert_eq!(std::mem::size_of::<GcHeader>(), 8);
}
#[test]
fn test_color_roundtrip() {
let mut h = GcHeader::new(0, 64);
assert_eq!(h.color(), GcColor::White);
h.set_color(GcColor::Gray);
assert_eq!(h.color(), GcColor::Gray);
h.set_color(GcColor::Black);
assert_eq!(h.color(), GcColor::Black);
h.set_color(GcColor::White);
assert_eq!(h.color(), GcColor::White);
}
#[test]
fn test_generation_roundtrip() {
let mut h = GcHeader::new(0, 64);
assert_eq!(h.generation(), Generation::Young);
h.set_generation(Generation::Old);
assert_eq!(h.generation(), Generation::Old);
h.set_color(GcColor::Gray);
assert_eq!(h.generation(), Generation::Old);
assert_eq!(h.color(), GcColor::Gray);
}
#[test]
fn test_forwarded_flag() {
let mut h = GcHeader::new(0, 64);
assert!(!h.is_forwarded());
h.set_forwarded(true);
assert!(h.is_forwarded());
assert_eq!(h.color(), GcColor::White);
assert_eq!(h.generation(), Generation::Young);
h.set_forwarded(false);
assert!(!h.is_forwarded());
}
}