#[repr(C)]
pub struct PrimitiveOption<T: Copy> {
pub has_value: u8,
pub _pad: [u8; 7],
pub value: T,
}
impl<T: Copy> PrimitiveOption<T> {
#[inline]
pub fn some(value: T) -> Self {
Self {
has_value: 1,
_pad: [0; 7],
value,
}
}
#[inline]
pub fn none() -> Self
where
T: Default,
{
Self {
has_value: 0,
_pad: [0; 7],
value: T::default(),
}
}
#[inline]
pub fn is_some(&self) -> bool {
self.has_value != 0
}
#[inline]
pub fn is_none(&self) -> bool {
self.has_value == 0
}
#[inline]
pub fn get(&self) -> Option<T> {
if self.is_some() {
Some(self.value)
} else {
None
}
}
}
pub type HeapOption<T> = *const T;
#[inline]
pub fn heap_option_is_none<T>(ptr: *const T) -> bool {
ptr.is_null()
}
#[inline]
pub fn heap_option_is_some<T>(ptr: *const T) -> bool {
!ptr.is_null()
}
pub const PRIMITIVE_OPTION_OFFSET_HAS_VALUE: usize = 0;
pub const PRIMITIVE_OPTION_OFFSET_VALUE: usize = 8;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_primitive_option_f64_some() {
let opt = PrimitiveOption::some(3.14f64);
assert!(opt.is_some());
assert!(!opt.is_none());
assert_eq!(opt.get(), Some(3.14f64));
}
#[test]
fn test_primitive_option_f64_none() {
let opt = PrimitiveOption::<f64>::none();
assert!(opt.is_none());
assert!(!opt.is_some());
assert_eq!(opt.get(), None);
}
#[test]
fn test_primitive_option_i64_some() {
let opt = PrimitiveOption::some(42i64);
assert!(opt.is_some());
assert_eq!(opt.get(), Some(42i64));
}
#[test]
fn test_primitive_option_i64_none() {
let opt = PrimitiveOption::<i64>::none();
assert!(opt.is_none());
assert_eq!(opt.get(), None);
}
#[test]
fn test_primitive_option_i32_some() {
let opt = PrimitiveOption::some(99i32);
assert!(opt.is_some());
assert_eq!(opt.get(), Some(99i32));
}
#[test]
fn test_primitive_option_i32_none() {
let opt = PrimitiveOption::<i32>::none();
assert!(opt.is_none());
assert_eq!(opt.get(), None);
}
#[test]
fn test_primitive_option_bool_some() {
let opt = PrimitiveOption::some(true);
assert!(opt.is_some());
assert_eq!(opt.get(), Some(true));
let opt_false = PrimitiveOption::some(false);
assert!(opt_false.is_some());
assert_eq!(opt_false.get(), Some(false));
}
#[test]
fn test_primitive_option_bool_none() {
let opt = PrimitiveOption::<bool>::none();
assert!(opt.is_none());
assert_eq!(opt.get(), None);
}
#[test]
fn test_size_of_primitive_option_f64() {
assert_eq!(std::mem::size_of::<PrimitiveOption<f64>>(), 16);
}
#[test]
fn test_size_of_primitive_option_i64() {
assert_eq!(std::mem::size_of::<PrimitiveOption<i64>>(), 16);
}
#[test]
fn test_size_of_primitive_option_i32() {
assert_eq!(std::mem::size_of::<PrimitiveOption<i32>>(), 12);
}
#[test]
fn test_size_of_primitive_option_bool() {
assert_eq!(std::mem::size_of::<PrimitiveOption<bool>>(), 9);
}
#[test]
fn test_field_offsets_f64() {
let opt = PrimitiveOption::some(1.0f64);
let base = &opt as *const _ as usize;
let has_value_offset = &opt.has_value as *const _ as usize - base;
let value_offset = &opt.value as *const _ as usize - base;
assert_eq!(has_value_offset, PRIMITIVE_OPTION_OFFSET_HAS_VALUE);
assert_eq!(value_offset, PRIMITIVE_OPTION_OFFSET_VALUE);
}
#[test]
fn test_heap_option_none() {
let ptr: HeapOption<u8> = std::ptr::null();
assert!(heap_option_is_none(ptr));
assert!(!heap_option_is_some(ptr));
}
#[test]
fn test_heap_option_some() {
let val: u8 = 42;
let ptr: HeapOption<u8> = &val as *const u8;
assert!(heap_option_is_some(ptr));
assert!(!heap_option_is_none(ptr));
}
#[test]
fn test_heap_option_is_pointer_sized() {
assert_eq!(std::mem::size_of::<HeapOption<u8>>(), 8);
assert_eq!(std::mem::size_of::<HeapOption<f64>>(), 8);
}
}