#[repr(i32)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum PcStatus {
Ok = 0,
NullPointer = -1,
BufferTooSmall = -2,
BadEncoding = -3,
Verification = -4,
Unsupported = -5,
Internal = -6,
WantRead = -7,
WantWrite = -8,
WantHandshake = -9,
Closed = -10,
TlsAlert = -11,
}
pub(super) fn guard(f: impl FnOnce() -> PcStatus) -> PcStatus {
std::panic::catch_unwind(std::panic::AssertUnwindSafe(f)).unwrap_or(PcStatus::Internal)
}
pub(super) fn guard_ptr<T>(f: impl FnOnce() -> *mut T) -> *mut T {
std::panic::catch_unwind(std::panic::AssertUnwindSafe(f)).unwrap_or(core::ptr::null_mut())
}
pub(super) fn guard_i32(sentinel: i32, f: impl FnOnce() -> i32) -> i32 {
std::panic::catch_unwind(std::panic::AssertUnwindSafe(f)).unwrap_or(sentinel)
}
pub(super) unsafe fn slice<'a>(ptr: *const u8, len: usize) -> Option<&'a [u8]> {
if len == 0 {
return Some(&[]);
}
if ptr.is_null() {
return None;
}
Some(unsafe { core::slice::from_raw_parts(ptr, len) })
}
pub(super) unsafe fn out_write(data: &[u8], out: *mut u8, out_len: *mut usize) -> PcStatus {
if out_len.is_null() {
return PcStatus::NullPointer;
}
let cap = unsafe { *out_len };
unsafe { *out_len = data.len() };
if data.len() > cap {
return PcStatus::BufferTooSmall;
}
if !data.is_empty() {
if out.is_null() {
return PcStatus::NullPointer;
}
unsafe { core::ptr::copy_nonoverlapping(data.as_ptr(), out, data.len()) };
}
PcStatus::Ok
}
#[cfg(test)]
mod tests {
#[test]
fn guard_catches_panic_returns_internal() {
let s = super::guard(|| panic!("test panic"));
assert_eq!(s, super::PcStatus::Internal);
}
#[test]
fn guard_ptr_catches_panic_and_returns_null() {
let p: *mut u8 = super::guard_ptr(|| panic!("test panic"));
assert!(p.is_null());
}
#[test]
fn guard_ptr_passes_value_through() {
let mut x = 7u8;
let p: *mut u8 = super::guard_ptr(|| &mut x as *mut u8);
assert!(!p.is_null());
}
#[test]
fn guard_i32_catches_panic_and_returns_sentinel() {
let v = super::guard_i32(-42, || panic!("test panic"));
assert_eq!(v, -42);
}
#[test]
fn guard_i32_passes_value_through() {
let v = super::guard_i32(-1, || 5);
assert_eq!(v, 5);
}
}