#![allow(dead_code)]
use core::ffi::c_int;
use core::ops::{Deref, DerefMut};
use core::ptr::NonNull;
use crate::ZeroDdsStatus;
pub(crate) struct Borrowed<'a, T: 'a>(&'a T);
impl<'a, T> Borrowed<'a, T> {
#[inline]
pub unsafe fn from_raw(ptr: *const T) -> Result<Self, ZeroDdsStatus> {
match unsafe { ptr.as_ref() } {
Some(r) => Ok(Borrowed(r)),
None => Err(ZeroDdsStatus::BadHandle),
}
}
}
impl<T> Deref for Borrowed<'_, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
self.0
}
}
pub(crate) struct OutPtr<T>(NonNull<T>);
impl<T> OutPtr<T> {
#[inline]
pub unsafe fn from_raw(ptr: *mut T) -> Result<Self, ZeroDdsStatus> {
NonNull::new(ptr)
.map(OutPtr)
.ok_or(ZeroDdsStatus::BadParameter)
}
#[inline]
pub fn write(self, value: T) {
unsafe { self.0.as_ptr().write(value) }
}
}
pub(crate) struct Owned<T>(Box<T>);
impl<T> Owned<T> {
#[inline]
pub fn new(value: T) -> Self {
Owned(Box::new(value))
}
#[inline]
pub fn into_raw(self) -> *mut T {
Box::into_raw(self.0)
}
#[inline]
pub unsafe fn from_raw_drop(ptr: *mut T) {
if !ptr.is_null() {
let _ = unsafe { Box::from_raw(ptr) };
}
}
}
pub(crate) struct BytesIn<'a>(&'a [u8]);
impl<'a> BytesIn<'a> {
#[inline]
pub unsafe fn from_raw(ptr: *const u8, len: usize) -> Result<Self, ZeroDdsStatus> {
if ptr.is_null() {
if len == 0 {
return Ok(BytesIn(&[]));
}
return Err(ZeroDdsStatus::BadParameter);
}
Ok(BytesIn(unsafe { core::slice::from_raw_parts(ptr, len) }))
}
}
impl Deref for BytesIn<'_> {
type Target = [u8];
#[inline]
fn deref(&self) -> &[u8] {
self.0
}
}
pub(crate) struct BytesOut<'a>(&'a mut [u8]);
impl<'a> BytesOut<'a> {
#[inline]
pub unsafe fn from_raw(ptr: *mut u8, len: usize) -> Result<Self, ZeroDdsStatus> {
if ptr.is_null() {
if len == 0 {
return Ok(BytesOut(&mut []));
}
return Err(ZeroDdsStatus::BadParameter);
}
Ok(BytesOut(unsafe {
core::slice::from_raw_parts_mut(ptr, len)
}))
}
}
impl Deref for BytesOut<'_> {
type Target = [u8];
#[inline]
fn deref(&self) -> &[u8] {
self.0
}
}
impl DerefMut for BytesOut<'_> {
#[inline]
fn deref_mut(&mut self) -> &mut [u8] {
self.0
}
}
pub(crate) struct CStrIn<'a>(&'a str);
impl<'a> CStrIn<'a> {
#[inline]
pub unsafe fn from_raw(ptr: *const core::ffi::c_char) -> Result<Self, ZeroDdsStatus> {
if ptr.is_null() {
return Err(ZeroDdsStatus::BadParameter);
}
let cs = unsafe { core::ffi::CStr::from_ptr(ptr) };
cs.to_str()
.map(CStrIn)
.map_err(|_| ZeroDdsStatus::InvalidUtf8)
}
}
impl Deref for CStrIn<'_> {
type Target = str;
#[inline]
fn deref(&self) -> &str {
self.0
}
}
#[inline]
pub(crate) fn status<T>(r: Result<T, ZeroDdsStatus>) -> c_int {
match r {
Ok(_) => ZeroDdsStatus::Ok as c_int,
Err(s) => s as c_int,
}
}
#[cfg(test)]
mod tests {
use super::*;
use core::ptr;
#[test]
fn borrowed_null_returns_bad_handle() {
let r: Result<Borrowed<'_, u32>, _> = unsafe { Borrowed::from_raw(ptr::null()) };
assert!(matches!(r, Err(ZeroDdsStatus::BadHandle)));
}
#[test]
fn borrowed_valid_derefs() {
let x: u32 = 42;
let b = unsafe { Borrowed::from_raw(&x as *const u32) }.unwrap();
assert_eq!(*b, 42);
}
#[test]
fn outptr_null_returns_bad_parameter() {
let r: Result<OutPtr<u32>, _> = unsafe { OutPtr::from_raw(ptr::null_mut()) };
assert!(matches!(r, Err(ZeroDdsStatus::BadParameter)));
}
#[test]
fn outptr_writes_exactly_once() {
let mut x: u32 = 0;
let out = unsafe { OutPtr::from_raw(&mut x as *mut u32) }.unwrap();
out.write(99);
assert_eq!(x, 99);
}
#[test]
fn owned_roundtrip_drops_on_from_raw() {
let o = Owned::new(String::from("alive"));
let raw = o.into_raw();
unsafe { Owned::from_raw_drop(raw) };
}
#[test]
fn owned_from_raw_drop_null_is_noop() {
unsafe { Owned::<u32>::from_raw_drop(ptr::null_mut()) };
}
#[test]
fn bytesin_null_with_len_zero_ok() {
let b = unsafe { BytesIn::from_raw(ptr::null(), 0) }.unwrap();
assert!(b.is_empty());
}
#[test]
fn bytesin_null_with_len_nonzero_errors() {
let r = unsafe { BytesIn::from_raw(ptr::null(), 4) };
assert!(matches!(r, Err(ZeroDdsStatus::BadParameter)));
}
#[test]
fn bytesin_valid_derefs() {
let data = [1u8, 2, 3, 4];
let b = unsafe { BytesIn::from_raw(data.as_ptr(), data.len()) }.unwrap();
assert_eq!(&*b, &data[..]);
}
#[test]
fn bytesout_null_with_len_zero_ok() {
let b = unsafe { BytesOut::from_raw(ptr::null_mut(), 0) }.unwrap();
assert!(b.is_empty());
}
#[test]
fn bytesout_valid_writes() {
let mut buf = [0u8; 4];
{
let mut b = unsafe { BytesOut::from_raw(buf.as_mut_ptr(), buf.len()) }.unwrap();
b[0] = 0xAA;
b[3] = 0xBB;
}
assert_eq!(buf, [0xAA, 0, 0, 0xBB]);
}
#[test]
fn cstrin_null_errors() {
let r = unsafe { CStrIn::from_raw(ptr::null()) };
assert!(matches!(r, Err(ZeroDdsStatus::BadParameter)));
}
#[test]
fn cstrin_valid_utf8_derefs() {
let s = c"hello";
let c = unsafe { CStrIn::from_raw(s.as_ptr()) }.unwrap();
assert_eq!(&*c, "hello");
}
#[test]
fn cstrin_invalid_utf8_errors() {
let bad: [core::ffi::c_char; 2] = [-1, 0];
let r = unsafe { CStrIn::from_raw(bad.as_ptr()) };
assert!(matches!(r, Err(ZeroDdsStatus::InvalidUtf8)));
}
#[test]
fn status_ok_returns_zero() {
let r: Result<(), ZeroDdsStatus> = Ok(());
assert_eq!(status(r), 0);
}
#[test]
fn status_err_returns_negative() {
let r: Result<(), ZeroDdsStatus> = Err(ZeroDdsStatus::BadHandle);
assert_eq!(status(r), ZeroDdsStatus::BadHandle as c_int);
}
}