use std::any::{Any, TypeId};
use std::borrow::Cow;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::sync::Arc;
pub use seq_macro::seq;
pub struct DefaultRegistry;
pub trait Capability: 'static {
type Handle: ?Sized + 'static;
}
#[derive(Clone)]
struct CastFn {
cast_ref: Arc<dyn Fn(&dyn Any) -> Option<[usize; 2]> + Send + Sync>,
cast_mut: Arc<dyn Fn(&mut dyn Any) -> Option<[usize; 2]> + Send + Sync>,
}
#[derive(Clone)]
pub struct CapabilityMap {
entries: HashMap<TypeId, CastFn>,
}
impl CapabilityMap {
pub fn new() -> Self {
Self { entries: HashMap::new() }
}
pub fn insert_cast<C: Capability>(
&mut self,
cast_ref: impl Fn(&dyn Any) -> Option<&C::Handle> + Send + Sync + 'static,
cast_mut: impl Fn(&mut dyn Any) -> Option<&mut C::Handle> + Send + Sync + 'static,
) {
self.entries.insert(TypeId::of::<C>(), CastFn {
cast_ref: Arc::new(move |any| {
let handle: &C::Handle = cast_ref(any)?;
Some(unsafe { std::mem::transmute_copy::<&C::Handle, [usize; 2]>(&handle) })
}),
cast_mut: Arc::new(move |any| {
let handle: &mut C::Handle = cast_mut(any)?;
Some(unsafe { std::mem::transmute_copy::<&mut C::Handle, [usize; 2]>(&handle) })
}),
});
}
pub fn has<C: Capability>(&self) -> bool {
self.entries.contains_key(&TypeId::of::<C>())
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
fn get_ref<C: Capability>(&self, data: &dyn Any) -> Option<[usize; 2]> {
let cast_fn = self.entries.get(&TypeId::of::<C>())?;
(cast_fn.cast_ref)(data)
}
fn get_mut<C: Capability>(&self, data: &mut dyn Any) -> Option<[usize; 2]> {
let cast_fn = self.entries.get(&TypeId::of::<C>())?;
(cast_fn.cast_mut)(data)
}
}
pub struct Envelope {
data: Box<dyn Any + Send + Sync>,
caps: CapabilityMap,
}
impl Envelope {
pub fn from_parts(data: impl Any + Send + Sync, caps: CapabilityMap) -> Self {
Self { data: Box::new(data), caps }
}
pub fn from_raw(data: Box<dyn Any + Send + Sync>, caps: CapabilityMap) -> Self {
Self { data, caps }
}
pub fn caps(&self) -> &CapabilityMap {
&self.caps
}
pub fn as_ref(&self) -> EnvelopeRef<'_> {
EnvelopeRef { data: &*self.data, caps: Cow::Borrowed(&self.caps) }
}
pub fn as_mut(&mut self) -> EnvelopeMut<'_> {
EnvelopeMut { data: &mut *self.data, caps: Cow::Borrowed(&self.caps) }
}
pub fn get<C: Capability>(&self) -> Option<&C::Handle> {
let fat = self.caps.get_ref::<C>(&*self.data)?;
unsafe { Some(&*std::mem::transmute_copy::<[usize; 2], *const C::Handle>(&fat)) }
}
pub fn get_mut<C: Capability>(&mut self) -> Option<&mut C::Handle> {
let fat = self.caps.get_mut::<C>(&mut *self.data)?;
unsafe { Some(&mut *std::mem::transmute_copy::<[usize; 2], *mut C::Handle>(&fat)) }
}
pub fn has<C: Capability>(&self) -> bool {
self.caps.has::<C>()
}
pub fn data<T: 'static>(&self) -> Option<&T> {
self.data.downcast_ref()
}
pub fn data_mut<T: 'static>(&mut self) -> Option<&mut T> {
self.data.downcast_mut()
}
pub fn into_data<T: 'static>(self) -> Option<T> {
self.data.downcast().ok().map(|b| *b)
}
pub fn capability_count(&self) -> usize {
self.caps.len()
}
}
pub struct EnvelopeRef<'a> {
data: &'a dyn Any,
caps: Cow<'a, CapabilityMap>,
}
impl<'a> EnvelopeRef<'a> {
pub fn from_parts(data: &'a dyn Any, caps: CapabilityMap) -> Self {
Self { data, caps: Cow::Owned(caps) }
}
pub fn caps(&self) -> &CapabilityMap {
&self.caps
}
pub fn get<C: Capability>(&self) -> Option<&C::Handle> {
let fat = self.caps.get_ref::<C>(self.data)?;
unsafe { Some(&*std::mem::transmute_copy::<[usize; 2], *const C::Handle>(&fat)) }
}
pub fn has<C: Capability>(&self) -> bool {
self.caps.has::<C>()
}
pub fn data<T: 'static>(&self) -> Option<&T> {
self.data.downcast_ref()
}
pub fn capability_count(&self) -> usize {
self.caps.len()
}
}
pub struct EnvelopeMut<'a> {
data: &'a mut dyn Any,
caps: Cow<'a, CapabilityMap>,
}
impl<'a> EnvelopeMut<'a> {
pub fn from_parts(data: &'a mut dyn Any, caps: CapabilityMap) -> Self {
Self { data, caps: Cow::Owned(caps) }
}
pub fn caps(&self) -> &CapabilityMap {
&self.caps
}
pub fn as_ref(&self) -> EnvelopeRef<'_> {
EnvelopeRef { data: self.data, caps: Cow::Borrowed(&self.caps) }
}
pub fn get<C: Capability>(&self) -> Option<&C::Handle> {
let fat = self.caps.get_ref::<C>(self.data)?;
unsafe { Some(&*std::mem::transmute_copy::<[usize; 2], *const C::Handle>(&fat)) }
}
pub fn get_mut<C: Capability>(&mut self) -> Option<&mut C::Handle> {
let fat = self.caps.get_mut::<C>(self.data)?;
unsafe { Some(&mut *std::mem::transmute_copy::<[usize; 2], *mut C::Handle>(&fat)) }
}
pub fn has<C: Capability>(&self) -> bool {
self.caps.has::<C>()
}
pub fn data<T: 'static>(&self) -> Option<&T> {
self.data.downcast_ref()
}
pub fn data_mut<T: 'static>(&mut self) -> Option<&mut T> {
self.data.downcast_mut()
}
pub fn capability_count(&self) -> usize {
self.caps.len()
}
}
pub trait Reflectable: Send + Sync + 'static {
fn reflect(self) -> Envelope;
fn reflect_ref(&self) -> EnvelopeRef<'_>;
fn reflect_mut(&mut self) -> EnvelopeMut<'_>;
}
#[macro_export]
macro_rules! impl_reflectable {
($ty:ty) => {
$crate::impl_reflectable!($ty, [{ registry: $crate::DefaultRegistry, slots: 0..256 }]);
};
($ty:ty, [$($registries:tt)*]) => {
impl $crate::Reflectable for $ty {
fn reflect(self) -> $crate::Envelope {
$crate::reflect!(self, [$($registries)*])
}
fn reflect_ref(&self) -> $crate::EnvelopeRef<'_> {
$crate::reflect_ref!(&*self, [$($registries)*])
}
fn reflect_mut(&mut self) -> $crate::EnvelopeMut<'_> {
$crate::reflect_mut!(&mut *self, [$($registries)*])
}
}
};
}
#[doc(hidden)]
pub struct Probe<'a, T, Registry, const N: u64>(pub &'a T, PhantomData<Registry>);
impl<'a, T, R, const N: u64> Probe<'a, T, R, N> {
#[inline(always)]
pub fn new(val: &'a T) -> Self {
Self(val, PhantomData)
}
}
#[doc(hidden)]
pub trait HasCap<Marker, Registry, const N: u64> {
fn probe(&self, caps: &mut CapabilityMap);
}
#[doc(hidden)]
pub trait NoCap<Registry, const N: u64> {
fn probe(&self, _caps: &mut CapabilityMap) {}
}
impl<T, R, const N: u64> NoCap<R, N> for &Probe<'_, T, R, N> {}
#[doc(hidden)]
#[macro_export]
macro_rules! probe_slot {
($msg:expr, $caps:expr, $registry:ty, $n:literal) => {{
use $crate::HasCap as _;
use $crate::NoCap as _;
(&$crate::Probe::<_, $registry, $n>::new($msg)).probe($caps);
}};
}
#[macro_export]
macro_rules! reflect {
($($args:tt)*) => { $crate::__reflect_internal!(@owned $($args)*) };
}
#[macro_export]
macro_rules! reflect_ref {
($($args:tt)*) => { $crate::__reflect_internal!(@ref $($args)*) };
}
#[macro_export]
macro_rules! reflect_mut {
($($args:tt)*) => { $crate::__reflect_internal!(@mut $($args)*) };
}
#[doc(hidden)]
#[macro_export]
macro_rules! __reflect_internal {
(@owned $msg:expr, [$($registries:tt)*]) => {{
let msg = $msg;
$crate::__reflect_core!(@owned, msg, &msg, [$($registries)*])
}};
(@ref & $msg:expr, [$($registries:tt)*]) => {{
let msg = &$msg;
$crate::__reflect_core!(@ref, msg, msg, [$($registries)*])
}};
(@mut &mut $msg:expr, [$($registries:tt)*]) => {{
let msg = &mut $msg;
$crate::__reflect_core!(@mut, msg, &*msg, [$($registries)*])
}};
(@owned $msg:expr) => {
$crate::__reflect_internal!(@owned $msg, [{ registry: $crate::DefaultRegistry, slots: 0..256 }])
};
(@ref & $msg:expr) => {
$crate::__reflect_internal!(@ref & $msg, [{ registry: $crate::DefaultRegistry, slots: 0..256 }])
};
(@mut &mut $msg:expr) => {
$crate::__reflect_internal!(@mut &mut $msg, [{ registry: $crate::DefaultRegistry, slots: 0..256 }])
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __reflect_core {
(@$mode:ident, $msg:ident, $probe:expr, [$({ registry: $registry:ty, slots: $start:literal..$end:literal }),* $(,)?]) => {{
let mut caps = $crate::CapabilityMap::new();
$( $crate::seq!(N in $start..$end { $crate::probe_slot!($probe, &mut caps, $registry, N); }); )*
$crate::__reflect_finish!(@$mode $msg, caps)
}};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __reflect_finish {
(@owned $msg:ident, $caps:ident) => {
$crate::Envelope::from_parts($msg, $caps)
};
(@ref $msg:ident, $caps:ident) => {
$crate::EnvelopeRef::from_parts($msg as &dyn std::any::Any, $caps)
};
(@mut $msg:ident, $caps:ident) => {
$crate::EnvelopeMut::from_parts($msg as &mut dyn std::any::Any, $caps)
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __reflect_probe {
($msg:expr, [$({ registry: $registry:ty, slots: $start:literal..$end:literal }),* $(,)?]) => {{
let mut caps = $crate::CapabilityMap::new();
$(
$crate::seq!(N in $start..$end {
$crate::probe_slot!($msg, &mut caps, $registry, N);
});
)*
caps
}};
}
#[macro_export]
macro_rules! register_capability {
($($input:tt)*) => {
$crate::__register_cap_parse! { [] @rest [$($input)*] }
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __register_cap_parse {
([$($parsed:tt)*] @rest []) => {
$crate::__register_cap_emit! { $($parsed)* }
};
([$($parsed:tt)*] @rest [registry = $registry:ty, $($rest:tt)*]) => {
$crate::__register_cap_parse! { [$($parsed)* @registry [$registry]] @rest [$($rest)*] }
};
([$($parsed:tt)*] @rest [slot = $slot:literal, $($rest:tt)*]) => {
$crate::__register_cap_parse! { [$($parsed)* @slot [$slot]] @rest [$($rest)*] }
};
([$($parsed:tt)*] @rest [cap = $cap:ty, $($rest:tt)*]) => {
$crate::__register_cap_parse! { [$($parsed)* @cap [$cap]] @rest [$($rest)*] }
};
([$($parsed:tt)*] @rest [trait_bound = $($rest:tt)+]) => {
$crate::__register_cap_munch! { @target trait_bound @parsed [$($parsed)*] @accum [] @rest [$($rest)+] }
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __register_cap_munch {
(@target $target:ident @parsed [$($parsed:tt)*] @accum [$($accum:tt)*] @rest [, registry = $($rest:tt)*]) => {
$crate::__register_cap_parse! { [$($parsed)* @$target [$($accum)*]] @rest [registry = $($rest)*] }
};
(@target $target:ident @parsed [$($parsed:tt)*] @accum [$($accum:tt)*] @rest [, slot = $($rest:tt)*]) => {
$crate::__register_cap_parse! { [$($parsed)* @$target [$($accum)*]] @rest [slot = $($rest)*] }
};
(@target $target:ident @parsed [$($parsed:tt)*] @accum [$($accum:tt)*] @rest [, cap = $($rest:tt)*]) => {
$crate::__register_cap_parse! { [$($parsed)* @$target [$($accum)*]] @rest [cap = $($rest)*] }
};
(@target $target:ident @parsed [$($parsed:tt)*] @accum [$($accum:tt)*] @rest [, trait_bound = $($rest:tt)*]) => {
$crate::__register_cap_parse! { [$($parsed)* @$target [$($accum)*]] @rest [trait_bound = $($rest)*] }
};
(@target $target:ident @parsed [$($parsed:tt)*] @accum [$($accum:tt)*] @rest []) => {
$crate::__register_cap_parse! { [$($parsed)* @$target [$($accum)*]] @rest [] }
};
(@target $target:ident @parsed [$($parsed:tt)*] @accum [$($accum:tt)*] @rest [,]) => {
$crate::__register_cap_parse! { [$($parsed)* @$target [$($accum)*]] @rest [] }
};
(@target $target:ident @parsed $parsed:tt @accum [$($accum:tt)*] @rest [$first:tt $($rest:tt)*]) => {
$crate::__register_cap_munch! { @target $target @parsed $parsed @accum [$($accum)* $first] @rest [$($rest)*] }
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __register_cap_emit {
($($input:tt)*) => {
$crate::__register_cap_norm! {
@registry [] @slot [] @cap [] @trait_bound []
@input [$($input)*]
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __register_cap_norm {
(@registry [$($registry:tt)*] @slot [$slot:literal] @cap [$cap:ty] @trait_bound [$($tb:tt)+]
@input []) => {
$crate::__register_cap_final! { @registry [$($registry)*] @slot [$slot] @cap [$cap] @trait_bound [$($tb)+] }
};
(@registry $r:tt @slot $s:tt @cap $c:tt @trait_bound $tb:tt
@input [@registry [$($registry:tt)*] $($rest:tt)*]) => {
$crate::__register_cap_norm! { @registry [$($registry)*] @slot $s @cap $c @trait_bound $tb @input [$($rest)*] }
};
(@registry $r:tt @slot $s:tt @cap $c:tt @trait_bound $tb:tt
@input [@slot [$($slot:tt)*] $($rest:tt)*]) => {
$crate::__register_cap_norm! { @registry $r @slot [$($slot)*] @cap $c @trait_bound $tb @input [$($rest)*] }
};
(@registry $r:tt @slot $s:tt @cap $c:tt @trait_bound $tb:tt
@input [@cap [$($cap:tt)*] $($rest:tt)*]) => {
$crate::__register_cap_norm! { @registry $r @slot $s @cap [$($cap)*] @trait_bound $tb @input [$($rest)*] }
};
(@registry $r:tt @slot $s:tt @cap $c:tt @trait_bound $tb:tt
@input [@trait_bound [$($bound:tt)*] $($rest:tt)*]) => {
$crate::__register_cap_norm! { @registry $r @slot $s @cap $c @trait_bound [$($bound)*] @input [$($rest)*] }
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __register_cap_final {
(@registry [] @slot [$slot:literal] @cap [$cap:ty] @trait_bound [$($bounds:tt)+]) => {
$crate::__register_cap_final! { @registry [$crate::DefaultRegistry] @slot [$slot] @cap [$cap] @trait_bound [$($bounds)+] }
};
(@registry [$registry:ty] @slot [$slot:literal] @cap [$cap:ty] @trait_bound [$($bounds:tt)+]) => {
impl<'a, T: $($bounds)+ + 'static> $crate::HasCap<$cap, $registry, $slot>
for $crate::Probe<'a, T, $registry, $slot>
{
fn probe(&self, caps: &mut $crate::CapabilityMap) {
caps.insert_cast::<$cap>(
|any| {
let val = any.downcast_ref::<T>()?;
Some(val as &<$cap as $crate::Capability>::Handle)
},
|any| {
let val = any.downcast_mut::<T>()?;
Some(val as &mut <$cap as $crate::Capability>::Handle)
},
);
}
}
};
}