use std::mem::{align_of, size_of};
pub const HEADER_SIZE: usize = size_of::<Header>();
pub const HEADER_ALIGN: usize = align_of::<Header>();
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(C)]
pub struct Header {
pub __content_size: usize,
}
impl Header {
#[inline(always)]
pub unsafe fn new_unchecked(content_size: usize, is_free: bool) -> Header {
debug_assert_eq!(content_size % 2, 0, "size should be even.");
match is_free {
true => (Header { __content_size: content_size }).tagged(),
false => Header { __content_size: content_size },
}
}
#[inline(always)]
pub fn tagged(&self) -> Header {
Header { __content_size: self.__content_size | 1 }
}
#[inline(always)]
pub fn untagged(&self) -> Header {
Header { __content_size: self.__content_size & !1 }
}
#[inline(always)]
pub fn is_tagged(&self) -> bool {
self.__content_size & 1 != 0
}
#[inline(always)]
pub fn content_size(&self) -> usize {
self.untagged().__content_size
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[cfg(debug_assertions)]
#[should_panic]
fn test_1() {
let _h = unsafe { Header::new_unchecked(21, false) };
}
#[test]
fn test_2() {
let h = unsafe {
Header::new_unchecked(20, true)
};
assert!(h.is_tagged());
assert_eq!(h.content_size(), 20);
assert_eq!(h.__content_size, 21);
let h = h.untagged();
assert_eq!(h.content_size(), 20);
assert_eq!(h.content_size(), h.__content_size);
}
#[test]
fn test_3() {
let h = unsafe {
Header::new_unchecked(20, false)
};
assert!(!h.is_tagged());
assert_eq!(h.content_size(), 20);
assert_eq!(h.content_size(), h.__content_size);
let h = h.tagged();
assert_eq!(h.content_size(), 20);
assert_eq!(h.__content_size, 21);
}
#[test]
fn test_4() {
let h = unsafe {
Header::new_unchecked(20, false)
};
assert_eq!(h.untagged(), h);
assert_eq!(h.tagged().untagged(), h);
}
#[test]
fn test_5() {
let h = unsafe {
Header::new_unchecked(20, true)
};
assert_eq!(h.tagged(), h);
assert_eq!(h.untagged().tagged(), h);
}
}