#![deny(unsafe_code)]
use std::fmt;
use std::fmt::{Debug, Formatter};
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::mem::ManuallyDrop;
use std::ops::Deref;
use crate::state_name::StateName;
use crate::type_id::{TypeId, GUID};
pub struct OwnedState<T>
where
T: ?Sized,
{
pub(crate) raw: RawState<T>,
}
impl<T> OwnedState<T>
where
T: ?Sized,
{
pub const fn state_name(&self) -> StateName {
self.raw.state_name()
}
pub fn leak(self) -> BorrowedState<'static, T> {
BorrowedState::from_raw(self.into_raw())
}
pub fn cast<U>(self) -> OwnedState<U>
where
U: ?Sized,
{
OwnedState::from_raw(self.into_raw().cast())
}
pub(crate) const fn from_raw(raw: RawState<T>) -> Self {
Self { raw }
}
pub(crate) fn into_raw(self) -> RawState<T> {
ManuallyDrop::new(self).raw
}
}
impl<T> PartialEq for OwnedState<T>
where
T: ?Sized,
{
fn eq(&self, other: &Self) -> bool {
self.raw == other.raw
}
}
impl<T> Eq for OwnedState<T> where T: ?Sized {}
impl<T> Hash for OwnedState<T>
where
T: ?Sized,
{
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.raw.hash(state);
}
}
impl<T> Debug for OwnedState<T>
where
T: ?Sized,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("OwnedState").field("raw", &self.raw).finish()
}
}
impl<T> Drop for OwnedState<T>
where
T: ?Sized,
{
fn drop(&mut self) {
let _ = self.raw.delete();
}
}
pub struct BorrowedState<'a, T>
where
T: ?Sized,
{
pub(crate) raw: RawState<T>,
_marker: PhantomData<&'a ()>,
}
impl<'a, T> BorrowedState<'a, T>
where
T: ?Sized,
{
pub const fn state_name(self) -> StateName {
self.raw.state_name()
}
pub const fn to_owned_state(self) -> OwnedState<T> {
OwnedState::from_raw(self.raw)
}
pub const fn cast<U>(self) -> BorrowedState<'a, U>
where
U: ?Sized,
{
BorrowedState::from_raw(self.raw.cast())
}
pub(crate) const fn from_raw(raw: RawState<T>) -> Self {
Self {
raw,
_marker: PhantomData,
}
}
}
impl<T> BorrowedState<'static, T>
where
T: ?Sized,
{
pub fn from_state_name(state_name: impl Into<StateName>) -> Self {
Self::from_raw(RawState::from_state_name_and_type_id(state_name.into(), TypeId::none()))
}
pub fn from_state_name_and_type_id(state_name: impl Into<StateName>, type_id: impl Into<GUID>) -> Self {
Self::from_raw(RawState::from_state_name_and_type_id(
state_name.into(),
TypeId::from_guid(type_id.into()),
))
}
}
impl<T> Copy for BorrowedState<'_, T> where T: ?Sized {}
impl<T> Clone for BorrowedState<'_, T>
where
T: ?Sized,
{
fn clone(&self) -> Self {
*self
}
}
impl<T> PartialEq for BorrowedState<'_, T>
where
T: ?Sized,
{
fn eq(&self, other: &Self) -> bool {
self.raw == other.raw
}
}
impl<T> Eq for BorrowedState<'_, T> where T: ?Sized {}
impl<T> Hash for BorrowedState<'_, T>
where
T: ?Sized,
{
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.raw.hash(state);
}
}
impl<T> Debug for BorrowedState<'_, T>
where
T: ?Sized,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("BorrowedState").field("raw", &self.raw).finish()
}
}
pub trait AsState: private::Sealed {
type Data: ?Sized;
fn as_state(&self) -> BorrowedState<'_, Self::Data>;
}
impl<T> AsState for OwnedState<T>
where
T: ?Sized,
{
type Data = T;
fn as_state(&self) -> BorrowedState<'_, T> {
BorrowedState::from_raw(self.raw)
}
}
impl<T> AsState for BorrowedState<'_, T>
where
T: ?Sized,
{
type Data = T;
fn as_state(&self) -> BorrowedState<'_, T> {
*self
}
}
impl<S> AsState for S
where
S: Deref,
S::Target: AsState,
{
type Data = <S::Target as AsState>::Data;
fn as_state(&self) -> BorrowedState<'_, Self::Data> {
self.deref().as_state()
}
}
pub(crate) struct RawState<T>
where
T: ?Sized,
{
pub(crate) state_name: StateName,
pub(crate) type_id: TypeId,
_marker: PhantomData<fn(T) -> T>,
}
impl<T> RawState<T>
where
T: ?Sized,
{
pub(crate) const fn from_state_name_and_type_id(state_name: StateName, type_id: TypeId) -> Self {
Self {
state_name,
type_id,
_marker: PhantomData,
}
}
const fn state_name(self) -> StateName {
self.state_name
}
pub(crate) const fn cast<U>(self) -> RawState<U>
where
U: ?Sized,
{
RawState::from_state_name_and_type_id(self.state_name, self.type_id)
}
}
impl<T> Copy for RawState<T> where T: ?Sized {}
impl<T> Clone for RawState<T>
where
T: ?Sized,
{
fn clone(&self) -> Self {
*self
}
}
impl<T> PartialEq for RawState<T>
where
T: ?Sized,
{
fn eq(&self, other: &Self) -> bool {
self.state_name == other.state_name && self.type_id == other.type_id
}
}
impl<T> Eq for RawState<T> where T: ?Sized {}
impl<T> Hash for RawState<T>
where
T: ?Sized,
{
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.state_name.hash(state);
self.type_id.hash(state);
}
}
impl<T> Debug for RawState<T>
where
T: ?Sized,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("RawState")
.field("state_name", &self.state_name)
.field("type_id", &self.type_id)
.finish()
}
}
mod private {
use std::ops::Deref;
use super::{BorrowedState, OwnedState};
pub trait Sealed {}
impl<T> Sealed for OwnedState<T> where T: ?Sized {}
impl<T> Sealed for BorrowedState<'_, T> where T: ?Sized {}
impl<S> Sealed for S
where
S: Deref,
S::Target: Sealed,
{
}
}
#[cfg(test)]
mod tests {
#![allow(dead_code)]
use static_assertions::{assert_impl_all, assert_not_impl_any};
use super::*;
#[test]
fn owned_state_is_send_and_sync_regardless_of_data_type() {
type NeitherSendNorSync = *const ();
assert_not_impl_any!(NeitherSendNorSync: Send, Sync);
assert_impl_all!(OwnedState<NeitherSendNorSync>: Send, Sync);
}
#[test]
fn borrowed_state_is_send_and_sync_regardless_of_data_type() {
type NeitherSendNorSync = *const ();
assert_not_impl_any!(NeitherSendNorSync: Send, Sync);
assert_impl_all!(BorrowedState<'_, NeitherSendNorSync>: Send, Sync);
}
}