use crate::{mutex::RwLock, AddOrRemovePtr};
use std::{collections::HashMap, marker::PhantomData, num::NonZeroUsize, ptr::NonNull};
pub trait KeyType {
type Real;
const IDENTIFIER: usize;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Key<Type> {
key: NonZeroUsize,
_marker: PhantomData<Type>,
}
impl<Type> Key<Type> {
#[inline]
pub fn from_raw(nzu: NonZeroUsize) -> Key<Type> {
Key {
key: nzu,
_marker: PhantomData,
}
}
#[inline]
pub fn into_raw(self) -> NonZeroUsize {
self.key
}
#[inline]
pub fn cast<OtherType>(self) -> Key<OtherType> {
Key {
key: self.key,
_marker: PhantomData,
}
}
}
impl<Type: KeyType> Key<Type> {
#[inline]
pub fn from_non_null(nn: NonNull<Type::Real>) -> Key<Type> {
Key::from_raw(
NonZeroUsize::new(nn.as_ptr() as *mut () as usize)
.expect("NonNull is expected to be null, this should always work"),
)
}
#[inline]
pub fn from_ptr(ptr: *mut Type::Real) -> Option<Key<Type>> {
NonZeroUsize::new(ptr as *mut () as usize).map(Key::from_raw)
}
#[inline]
pub fn as_non_null(self) -> NonNull<Type::Real> {
NonNull::new(self.key.get() as *mut () as *mut Type::Real)
.expect("Should always be non-null")
}
#[inline]
pub fn as_ptr(self) -> *mut Type::Real {
self.key.get() as *mut Type::Real
}
#[inline]
pub fn identifier(self) -> usize {
Type::IDENTIFIER
}
#[inline]
pub fn verifiable(self) -> (NonZeroUsize, usize) {
(self.key, Type::IDENTIFIER)
}
}
#[derive(Debug)]
pub(crate) struct KeyServer {
pointers: RwLock<HashMap<NonZeroUsize, usize>>,
}
impl KeyServer {
#[inline]
pub(crate) fn new() -> KeyServer {
KeyServer {
pointers: RwLock::new(HashMap::new()),
}
}
#[inline]
pub(crate) fn process_new_pointers<I: IntoIterator<Item = AddOrRemovePtr>>(&self, pointers: I) {
let mut lock = None;
pointers.into_iter().for_each(|dir| match dir {
AddOrRemovePtr::DoNothing => {}
AddOrRemovePtr::AddPtr(ptr, ty) => {
lock.get_or_insert_with(|| self.pointers.write())
.insert(ptr, ty);
}
AddOrRemovePtr::RemovePtr(ptr) => {
lock.get_or_insert_with(|| self.pointers.write())
.remove(&ptr);
}
});
}
#[inline]
pub(crate) fn verify_pointers<I: IntoIterator<Item = (NonZeroUsize, usize)>>(
&self,
pointers: I,
) -> Result<(), NonZeroUsize> {
let lock = self.pointers.read();
pointers.into_iter().try_for_each(|(pointer, ty)| {
if lock.get(&pointer).copied() == Some(ty) {
Ok(())
} else {
Err(pointer)
}
})
}
}
#[macro_export]
macro_rules! key_type {
(
$(#[$meta: meta])*
$vis: vis struct $tyname: ident ( $foreign: ident ) : [$traitname: ident, $value: expr] ;
) => {
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[doc = "An object used to parameterize `Key`s representing a foreign pointer to"]
#[doc = concat!("an object of type `", stringify!($foreign), "`.")]
$vis struct $traitname;
impl $crate::KeyType for $traitname {
type Real = $foreign;
const IDENTIFIER: usize = $value;
}
$(#[$meta])*
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
$vis struct $tyname ( $crate::Key<$traitname> );
impl $tyname {
#[doc = concat!("Creates a new `", stringify!($tyname), "` from an appropriately typed key.")]
#[inline]
pub fn from_key(key: $crate::Key<$traitname>) -> Self {
Self(key)
}
#[doc = concat!("Gets the inner key for a `", stringify!($tyname), "`.")]
#[inline]
pub fn into_key(self) -> $crate::Key<$traitname> {
self.0
}
#[doc = concat!("Constructs a `", stringify!($tyname), "` from a non-zero `usize` representing a")]
#[doc = concat!("pointer to a `", stringify!($foreign), "`.")]
#[inline]
pub fn from_raw(raw: std::num::NonZeroUsize) -> Self {
Self::from_key($crate::Key::from_raw(raw))
}
#[doc = concat!("Get the backing `NonZeroUsize` from this `", stringify!($tyname), "`.")]
#[inline]
pub fn into_raw(self) -> NonZeroUsize {
self.into_key().into_raw()
}
#[doc = concat!("Creates a new `", stringify!($tyname), "` from a non-null pointer to a ")]
#[doc = concat!("`", stringify!($foreign), "`.")]
#[inline]
pub fn from_non_null(nn: std::ptr::NonNull<$foreign>) -> Self {
Self::from_key($crate::Key::from_non_null(nn))
}
#[doc = concat!("Creates a new `", stringify!($tyname), "` from a pointer to a ")]
#[doc = concat!("`", stringify!($foreign), "`. If the pointer is null, this function returns")]
#[doc = "`None`."]
#[inline]
pub fn from_ptr(ptr: *mut $foreign) -> Option<Self> {
$crate::Key::from_ptr(ptr).map(Self::from_key)
}
#[doc = concat!("Converts this `", stringify!($tyname), "` into a non-null pointer to a ")]
#[doc = concat!("`", stringify!($foreign), "`.")]
#[inline]
pub fn as_non_null(self) -> std::ptr::NonNull<$foreign> {
self.0.as_non_null()
}
#[doc = concat!("Converts this `", stringify!($tyname), "` into a pointer to a `")]
#[doc = concat!(stringify!($foreign), "`.")]
#[inline]
pub fn as_ptr(self) -> *mut $foreign {
self.0.as_ptr()
}
#[doc = concat!("Get an identifier that identifies that this `", stringify!($tyname), "` ")]
#[doc = concat!("refers to an object of type `", stringify!($foreign), "`.")]
#[inline]
pub fn identifier(self) -> usize {
$value
}
#[doc = concat!("Get a bundle consisting of this `", stringify!($tyname), "`'s backing pointer")]
#[doc = "and its identifier. Useful for passing into `Directive::pointers()`"]
#[inline]
pub fn verifiable(self) -> (NonZeroUsize, usize) {
(self.into_raw(), $value)
}
}
}
}