use super::string_obj::StringObj;
pub const RESULT_TAG_OK: u8 = 0;
pub const RESULT_TAG_ERR: u8 = 1;
#[repr(C)]
pub struct ResultF64Str {
pub tag: u8,
pub _pad: [u8; 7],
payload: u64, }
impl ResultF64Str {
#[inline]
pub fn ok(value: f64) -> Self {
Self {
tag: RESULT_TAG_OK,
_pad: [0; 7],
payload: value.to_bits(),
}
}
#[inline]
pub fn err(err_ptr: *const StringObj) -> Self {
Self {
tag: RESULT_TAG_ERR,
_pad: [0; 7],
payload: err_ptr as u64,
}
}
#[inline]
pub fn is_ok(&self) -> bool {
self.tag == RESULT_TAG_OK
}
#[inline]
pub fn is_err(&self) -> bool {
self.tag == RESULT_TAG_ERR
}
#[inline]
pub fn unwrap_ok(&self) -> f64 {
debug_assert!(self.is_ok());
f64::from_bits(self.payload)
}
#[inline]
pub fn unwrap_err(&self) -> *const StringObj {
debug_assert!(self.is_err());
self.payload as *const StringObj
}
}
#[repr(C)]
pub struct ResultI64Str {
pub tag: u8,
pub _pad: [u8; 7],
payload: u64, }
impl ResultI64Str {
#[inline]
pub fn ok(value: i64) -> Self {
Self {
tag: RESULT_TAG_OK,
_pad: [0; 7],
payload: value as u64,
}
}
#[inline]
pub fn err(err_ptr: *const StringObj) -> Self {
Self {
tag: RESULT_TAG_ERR,
_pad: [0; 7],
payload: err_ptr as u64,
}
}
#[inline]
pub fn is_ok(&self) -> bool {
self.tag == RESULT_TAG_OK
}
#[inline]
pub fn is_err(&self) -> bool {
self.tag == RESULT_TAG_ERR
}
#[inline]
pub fn unwrap_ok(&self) -> i64 {
debug_assert!(self.is_ok());
self.payload as i64
}
#[inline]
pub fn unwrap_err(&self) -> *const StringObj {
debug_assert!(self.is_err());
self.payload as *const StringObj
}
}
#[repr(C)]
pub struct ResultPtrStr {
pub tag: u8,
pub _pad: [u8; 7],
payload: u64, }
impl ResultPtrStr {
#[inline]
pub fn ok(ptr: *const u8) -> Self {
Self {
tag: RESULT_TAG_OK,
_pad: [0; 7],
payload: ptr as u64,
}
}
#[inline]
pub fn err(err_ptr: *const StringObj) -> Self {
Self {
tag: RESULT_TAG_ERR,
_pad: [0; 7],
payload: err_ptr as u64,
}
}
#[inline]
pub fn is_ok(&self) -> bool {
self.tag == RESULT_TAG_OK
}
#[inline]
pub fn is_err(&self) -> bool {
self.tag == RESULT_TAG_ERR
}
#[inline]
pub fn unwrap_ok(&self) -> *const u8 {
debug_assert!(self.is_ok());
self.payload as *const u8
}
#[inline]
pub fn unwrap_err(&self) -> *const StringObj {
debug_assert!(self.is_err());
self.payload as *const StringObj
}
}
pub const RESULT_OFFSET_TAG: usize = 0;
pub const RESULT_OFFSET_PAYLOAD: usize = 8;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_result_f64_ok() {
let r = ResultF64Str::ok(3.14);
assert!(r.is_ok());
assert!(!r.is_err());
assert!((r.unwrap_ok() - 3.14).abs() < f64::EPSILON);
}
#[test]
fn test_result_f64_err() {
let err = StringObj::new("something went wrong");
let r = ResultF64Str::err(err);
assert!(r.is_err());
assert!(!r.is_ok());
assert_eq!(r.unwrap_err(), err as *const StringObj);
unsafe { StringObj::drop(err) };
}
#[test]
fn test_size_of_result_f64_str() {
assert_eq!(std::mem::size_of::<ResultF64Str>(), 16);
}
#[test]
fn test_result_i64_ok() {
let r = ResultI64Str::ok(42);
assert!(r.is_ok());
assert_eq!(r.unwrap_ok(), 42);
}
#[test]
fn test_result_i64_ok_negative() {
let r = ResultI64Str::ok(-100);
assert!(r.is_ok());
assert_eq!(r.unwrap_ok(), -100);
}
#[test]
fn test_result_i64_err() {
let err = StringObj::new("i64 error");
let r = ResultI64Str::err(err);
assert!(r.is_err());
assert_eq!(r.unwrap_err(), err as *const StringObj);
unsafe { StringObj::drop(err) };
}
#[test]
fn test_size_of_result_i64_str() {
assert_eq!(std::mem::size_of::<ResultI64Str>(), 16);
}
#[test]
fn test_result_ptr_ok() {
let val: u8 = 99;
let r = ResultPtrStr::ok(&val as *const u8);
assert!(r.is_ok());
assert_eq!(r.unwrap_ok(), &val as *const u8);
}
#[test]
fn test_result_ptr_err() {
let err = StringObj::new("ptr error");
let r = ResultPtrStr::err(err);
assert!(r.is_err());
assert_eq!(r.unwrap_err(), err as *const StringObj);
unsafe { StringObj::drop(err) };
}
#[test]
fn test_size_of_result_ptr_str() {
assert_eq!(std::mem::size_of::<ResultPtrStr>(), 16);
}
#[test]
fn test_result_field_offsets() {
let r = ResultF64Str::ok(1.0);
let base = &r as *const _ as usize;
let tag_offset = &r.tag as *const _ as usize - base;
let payload_offset = &r.payload as *const _ as usize - base;
assert_eq!(tag_offset, RESULT_OFFSET_TAG);
assert_eq!(payload_offset, RESULT_OFFSET_PAYLOAD);
}
#[test]
fn test_tag_constants() {
assert_eq!(RESULT_TAG_OK, 0);
assert_eq!(RESULT_TAG_ERR, 1);
assert_ne!(RESULT_TAG_OK, RESULT_TAG_ERR);
}
}