#![allow(unsafe_code)]
#![warn(missing_docs)]
#![warn(clippy::pedantic)]
#![deny(clippy::complexity)]
#![deny(clippy::cognitive_complexity)]
#![allow(clippy::needless_return)] #![doc(html_no_source)]
#![no_std]
#[cfg(all(feature = "alloc", not(feature = "std")))]
extern crate alloc;
#[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::boxed::Box;
#[cfg(feature = "std")]
extern crate std;
#[cfg(feature = "std")]
use std::boxed::Box;
#[cfg(all(feature = "std", feature = "lender"))]
#[macro_use]
extern crate lazy_static;
#[cfg(all(feature = "std", feature = "lender"))]
use std::collections::HashSet;
#[cfg(all(feature = "std", feature = "lender"))]
use std::sync::RwLock;
#[cfg(all(feature = "std", feature = "c-types"))]
pub mod c;
pub mod error;
use error::PointerError;
#[cfg(all(feature = "std", feature = "lender"))]
lazy_static! {
static ref LENT_POINTERS: RwLock<HashSet<usize>> = RwLock::new(HashSet::new());
}
#[inline]
fn validate_pointer_is_not_null<T>(pointer: *const T) -> Result<(), PointerError> {
if pointer.is_null() {
log::error!("Using a NULL pointer as an opaque pointer to Rust's data");
return Err(PointerError::Null);
}
return Ok(());
}
#[inline]
fn validate_pointer<T>(pointer: *const T) -> Result<(), PointerError> {
validate_pointer_is_not_null(pointer)?;
#[cfg(all(feature = "std", feature = "lender"))]
if let Ok(lent_pointers) = LENT_POINTERS.read() {
if !lent_pointers.contains(&(pointer as usize)) {
log::error!("Using an invalid pointer as an opaque pointer to Rust's data");
return Err(PointerError::Invalid);
}
} else {
log::error!("RwLock poisoned, it is not possible to check pointers");
return Err(PointerError::Invalid);
}
return Ok(());
}
#[cfg(any(feature = "alloc", feature = "std"))]
#[inline]
pub fn raw<T>(data: T) -> *mut T {
let pointer = Box::into_raw(Box::new(data));
#[cfg(all(feature = "std", feature = "lender"))]
LENT_POINTERS.write().unwrap().insert(pointer as usize);
return pointer;
}
#[deprecated(since = "0.7.2", note = "Use own_back<T>() instead")]
#[cfg(any(feature = "alloc", feature = "std"))]
#[inline]
pub unsafe fn free<T>(pointer: *mut T) {
std::mem::drop(own_back(pointer));
}
#[doc(alias = "free")]
#[cfg(any(feature = "alloc", feature = "std"))]
#[inline]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub unsafe fn own_back<T>(pointer: *mut T) -> Result<T, PointerError> {
validate_pointer(pointer)?;
let boxed = { Box::from_raw(pointer) };
#[cfg(all(feature = "std", feature = "lender"))]
LENT_POINTERS.write().unwrap().remove(&(pointer as usize));
return Ok(*boxed);
}
#[inline]
pub unsafe fn object<'a, T>(pointer: *const T) -> Result<&'a T, PointerError> {
validate_pointer_is_not_null(pointer)?;
return Ok(&*pointer);
}
#[inline]
pub unsafe fn mut_object<'a, T>(pointer: *mut T) -> Result<&'a mut T, PointerError> {
validate_pointer_is_not_null(pointer)?;
return Ok(&mut *pointer);
}