#![no_std]
#![deny(warnings, missing_docs)]
pub trait AsRaw {
type Raw: Unpin + 'static;
unsafe fn as_raw(&self) -> Self::Raw;
}
pub trait ContextResource<'ctx, Ctx> {
type Spore: ContextSpore<Ctx, Resource<'ctx> = Self>
where
Ctx: 'ctx;
fn sporulate(self) -> Self::Spore;
}
pub trait ContextSpore<Ctx>: 'static + Send + Sync {
type Resource<'ctx>: ContextResource<'ctx, Ctx, Spore = Self>
where
Ctx: 'ctx;
fn sprout(self, ctx: &Ctx) -> Self::Resource<'_>;
fn sprout_ref<'ctx>(&'ctx self, ctx: &'ctx Ctx) -> &'ctx Self::Resource<'ctx>;
fn sprout_mut<'ctx>(&'ctx mut self, ctx: &'ctx Ctx) -> &'ctx mut Self::Resource<'ctx>;
}
#[macro_export]
macro_rules! spore_convention {
($spore:ty) => {
unsafe impl Send for $spore {}
unsafe impl Sync for $spore {}
impl Drop for $spore {
#[inline]
fn drop(&mut self) {
unreachable!("Never drop ContextSpore");
}
}
};
}
pub struct RawContainer<Ctx: Unpin + 'static, Rss: Unpin + 'static> {
pub ctx: Ctx,
pub rss: Rss,
}
#[macro_export]
macro_rules! impl_spore {
($resource:ident and $spore:ident by ($ctx:ty, $rss:ty)) => {
#[repr(transparent)]
pub struct $resource<'ctx>(
$crate::RawContainer<<$ctx as $crate::AsRaw>::Raw, $rss>,
std::marker::PhantomData<&'ctx ()>,
);
impl<'ctx> $resource<'ctx> {
#[inline]
pub fn ctx(&self) -> &'ctx $ctx {
unsafe { <$ctx>::from_raw(&self.0.ctx) }
}
}
#[repr(transparent)]
pub struct $spore($crate::RawContainer<<$ctx as $crate::AsRaw>::Raw, $rss>);
$crate::spore_convention!($spore);
impl $crate::ContextSpore<$ctx> for $spore {
type Resource<'ctx> = $resource<'ctx>;
#[inline]
fn sprout(self, ctx: &$ctx) -> Self::Resource<'_> {
assert_eq!(self.0.ctx, unsafe { <$ctx as $crate::AsRaw>::as_raw(ctx) });
let ans = unsafe { std::mem::transmute_copy(&self.0) };
std::mem::forget(self);
ans
}
#[inline]
fn sprout_ref<'ctx>(&'ctx self, ctx: &'ctx $ctx) -> &Self::Resource<'_> {
assert_eq!(self.0.ctx, unsafe { <$ctx as $crate::AsRaw>::as_raw(ctx) });
unsafe { std::mem::transmute(&self.0) }
}
#[inline]
fn sprout_mut<'ctx>(&'ctx mut self, ctx: &'ctx $ctx) -> &mut Self::Resource<'_> {
assert_eq!(self.0.ctx, unsafe { <$ctx as $crate::AsRaw>::as_raw(ctx) });
unsafe { std::mem::transmute(&mut self.0) }
}
}
impl<'ctx> $crate::ContextResource<'ctx, $ctx> for $resource<'ctx> {
type Spore = $spore;
#[inline]
fn sporulate(self) -> Self::Spore {
let s = unsafe { std::mem::transmute_copy(&self.0) };
std::mem::forget(self);
$spore(s)
}
}
};
}