use std::marker::PhantomData;
#[non_exhaustive]
pub struct Value<RType, CType>
where
RType: Sized,
CType: Sized + From<RType> + Into<RType>,
{
_phantom: PhantomData<(RType, CType)>,
}
impl<RType, CType> Value<RType, CType>
where
RType: Sized,
CType: Sized + From<RType> + Into<RType>,
{
pub fn take(cval: CType) -> RType {
cval.into()
}
pub fn return_val(rval: RType) -> CType {
CType::from(rval)
}
pub unsafe fn to_out_param(rval: RType, arg_out: *mut CType) {
if !arg_out.is_null() {
unsafe { *arg_out = CType::from(rval) };
}
}
pub unsafe fn to_out_param_nonnull(rval: RType, arg_out: *mut CType) {
if arg_out.is_null() {
panic!("out param pointer is NULL");
}
unsafe { *arg_out = CType::from(rval) };
}
}
#[cfg(test)]
mod test {
use super::*;
use std::mem;
#[allow(non_camel_case_types)]
#[derive(Clone, Debug, PartialEq, Eq)]
struct result_t {
is_ok: bool,
error_code: u32,
}
impl Into<Result<(), u32>> for result_t {
fn into(self) -> Result<(), u32> {
if self.is_ok {
Ok(())
} else {
Err(self.error_code)
}
}
}
impl From<Result<(), u32>> for result_t {
fn from(res: Result<(), u32>) -> result_t {
match res {
Ok(_) => result_t {
is_ok: true,
error_code: 0,
},
Err(error_code) => result_t {
is_ok: false,
error_code,
},
}
}
}
type ResultValue = Value<Result<(), u32>, result_t>;
#[test]
fn take_and_return() {
let cval = result_t {
is_ok: false,
error_code: 13,
};
let rval = ResultValue::take(cval.clone());
assert_eq!(rval, Err(13));
assert_eq!(ResultValue::return_val(rval), cval);
}
#[test]
fn to_out_param() {
let mut cval = mem::MaybeUninit::uninit();
unsafe {
ResultValue::to_out_param(Ok(()), cval.as_mut_ptr());
}
assert_eq!(ResultValue::take(unsafe { cval.assume_init() }), Ok(()));
}
#[test]
fn to_out_param_null() {
unsafe {
ResultValue::to_out_param(Ok(()), std::ptr::null_mut());
}
}
#[test]
fn to_out_param_nonnull() {
let mut cval = mem::MaybeUninit::uninit();
unsafe {
ResultValue::to_out_param_nonnull(Ok(()), cval.as_mut_ptr());
}
assert_eq!(ResultValue::take(unsafe { cval.assume_init() }), Ok(()));
}
#[test]
#[should_panic]
fn to_out_param_nonnull_null() {
unsafe {
ResultValue::to_out_param_nonnull(Ok(()), std::ptr::null_mut());
}
}
}