use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::Arc;
use linkme::distributed_slice;
use once_cell::sync::Lazy;
pub use intertrait_macros::*;
use crate::hasher::BuildFastHasher;
pub mod cast;
mod hasher;
#[doc(hidden)]
pub type BoxedCaster = Box<dyn Any + Send + Sync>;
#[cfg(doctest)]
doc_comment::doctest!("../README.md");
#[doc(hidden)]
#[distributed_slice]
pub static CASTERS: [fn() -> (TypeId, BoxedCaster)] = [..];
static CASTER_MAP: Lazy<HashMap<(TypeId, TypeId), BoxedCaster, BuildFastHasher>> =
Lazy::new(|| {
CASTERS
.iter()
.map(|f| {
let (type_id, caster) = f();
((type_id, (*caster).type_id()), caster)
})
.collect()
});
fn cast_arc_panic<T: ?Sized + 'static>(_: Arc<dyn Any + Sync + Send>) -> Arc<T> {
panic!("Prepend [sync] to the list of target traits for Sync + Send types")
}
#[doc(hidden)]
pub struct Caster<T: ?Sized + 'static> {
pub cast_ref: fn(from: &dyn Any) -> &T,
pub cast_mut: fn(from: &mut dyn Any) -> &mut T,
pub cast_box: fn(from: Box<dyn Any>) -> Box<T>,
pub cast_rc: fn(from: Rc<dyn Any>) -> Rc<T>,
pub cast_arc: fn(from: Arc<dyn Any + Sync + Send + 'static>) -> Arc<T>,
}
impl<T: ?Sized + 'static> Caster<T> {
pub fn new(
cast_ref: fn(from: &dyn Any) -> &T,
cast_mut: fn(from: &mut dyn Any) -> &mut T,
cast_box: fn(from: Box<dyn Any>) -> Box<T>,
cast_rc: fn(from: Rc<dyn Any>) -> Rc<T>,
) -> Caster<T> {
Caster::<T> {
cast_ref,
cast_mut,
cast_box,
cast_rc,
cast_arc: cast_arc_panic,
}
}
pub fn new_sync(
cast_ref: fn(from: &dyn Any) -> &T,
cast_mut: fn(from: &mut dyn Any) -> &mut T,
cast_box: fn(from: Box<dyn Any>) -> Box<T>,
cast_rc: fn(from: Rc<dyn Any>) -> Rc<T>,
cast_arc: fn(from: Arc<dyn Any + Sync + Send>) -> Arc<T>,
) -> Caster<T> {
Caster::<T> {
cast_ref,
cast_mut,
cast_box,
cast_rc,
cast_arc,
}
}
}
fn caster<T: ?Sized + 'static>(type_id: TypeId) -> Option<&'static Caster<T>> {
CASTER_MAP
.get(&(type_id, TypeId::of::<Caster<T>>()))
.and_then(|caster| caster.downcast_ref::<Caster<T>>())
}
pub trait CastFrom: Any + 'static {
fn ref_any(&self) -> &dyn Any;
fn mut_any(&mut self) -> &mut dyn Any;
fn box_any(self: Box<Self>) -> Box<dyn Any>;
fn rc_any(self: Rc<Self>) -> Rc<dyn Any>;
}
pub trait CastFromSync: CastFrom + Sync + Send + 'static {
fn arc_any(self: Arc<Self>) -> Arc<dyn Any + Sync + Send + 'static>;
}
impl<T: Sized + Any + 'static> CastFrom for T {
fn ref_any(&self) -> &dyn Any {
self
}
fn mut_any(&mut self) -> &mut dyn Any {
self
}
fn box_any(self: Box<Self>) -> Box<dyn Any> {
self
}
fn rc_any(self: Rc<Self>) -> Rc<dyn Any> {
self
}
}
impl CastFrom for dyn Any + 'static {
fn ref_any(&self) -> &dyn Any {
self
}
fn mut_any(&mut self) -> &mut dyn Any {
self
}
fn box_any(self: Box<Self>) -> Box<dyn Any> {
self
}
fn rc_any(self: Rc<Self>) -> Rc<dyn Any> {
self
}
}
impl<T: Sized + Sync + Send + 'static> CastFromSync for T {
fn arc_any(self: Arc<Self>) -> Arc<dyn Any + Sync + Send + 'static> {
self
}
}
impl CastFrom for dyn Any + Sync + Send + 'static {
fn ref_any(&self) -> &dyn Any {
self
}
fn mut_any(&mut self) -> &mut dyn Any {
self
}
fn box_any(self: Box<Self>) -> Box<dyn Any> {
self
}
fn rc_any(self: Rc<Self>) -> Rc<dyn Any> {
self
}
}
impl CastFromSync for dyn Any + Sync + Send + 'static {
fn arc_any(self: Arc<Self>) -> Arc<dyn Any + Sync + Send + 'static> {
self
}
}
#[cfg(test)]
mod tests {
use std::any::{Any, TypeId};
use std::fmt::{Debug, Display};
use linkme::distributed_slice;
use crate::{BoxedCaster, CastFromSync};
use super::cast::*;
use super::*;
#[distributed_slice(super::CASTERS)]
static TEST_CASTER: fn() -> (TypeId, BoxedCaster) = create_test_caster;
#[derive(Debug)]
struct TestStruct;
trait SourceTrait: CastFromSync {}
impl SourceTrait for TestStruct {}
fn create_test_caster() -> (TypeId, BoxedCaster) {
let type_id = TypeId::of::<TestStruct>();
let caster = Box::new(Caster::<dyn Debug> {
cast_ref: |from| from.downcast_ref::<TestStruct>().unwrap(),
cast_mut: |from| from.downcast_mut::<TestStruct>().unwrap(),
cast_box: |from| from.downcast::<TestStruct>().unwrap(),
cast_rc: |from| from.downcast::<TestStruct>().unwrap(),
cast_arc: |from| from.downcast::<TestStruct>().unwrap(),
});
(type_id, caster)
}
#[test]
fn cast_ref() {
let ts = TestStruct;
let st: &dyn SourceTrait = &ts;
let debug = st.cast::<dyn Debug>();
assert!(debug.is_some());
}
#[test]
fn cast_mut() {
let mut ts = TestStruct;
let st: &mut dyn SourceTrait = &mut ts;
let debug = st.cast::<dyn Debug>();
assert!(debug.is_some());
}
#[test]
fn cast_box() {
let ts = Box::new(TestStruct);
let st: Box<dyn SourceTrait> = ts;
let debug = st.cast::<dyn Debug>();
assert!(debug.is_ok());
}
#[test]
fn cast_rc() {
let ts = Rc::new(TestStruct);
let st: Rc<dyn SourceTrait> = ts;
let debug = st.cast::<dyn Debug>();
assert!(debug.is_ok());
}
#[test]
fn cast_arc() {
let ts = Arc::new(TestStruct);
let st: Arc<dyn SourceTrait> = ts;
let debug = st.cast::<dyn Debug>();
assert!(debug.is_ok());
}
#[test]
fn cast_ref_wrong() {
let ts = TestStruct;
let st: &dyn SourceTrait = &ts;
let display = st.cast::<dyn Display>();
assert!(display.is_none());
}
#[test]
fn cast_mut_wrong() {
let mut ts = TestStruct;
let st: &mut dyn SourceTrait = &mut ts;
let display = st.cast::<dyn Display>();
assert!(display.is_none());
}
#[test]
fn cast_box_wrong() {
let ts = Box::new(TestStruct);
let st: Box<dyn SourceTrait> = ts;
let display = st.cast::<dyn Display>();
assert!(display.is_err());
}
#[test]
fn cast_rc_wrong() {
let ts = Rc::new(TestStruct);
let st: Rc<dyn SourceTrait> = ts;
let display = st.cast::<dyn Display>();
assert!(display.is_err());
}
#[test]
fn cast_arc_wrong() {
let ts = Arc::new(TestStruct);
let st: Arc<dyn SourceTrait> = ts;
let display = st.cast::<dyn Display>();
assert!(display.is_err());
}
#[test]
fn cast_ref_from_any() {
let ts = TestStruct;
let st: &dyn Any = &ts;
let debug = st.cast::<dyn Debug>();
assert!(debug.is_some());
}
#[test]
fn cast_mut_from_any() {
let mut ts = TestStruct;
let st: &mut dyn Any = &mut ts;
let debug = st.cast::<dyn Debug>();
assert!(debug.is_some());
}
#[test]
fn cast_box_from_any() {
let ts = Box::new(TestStruct);
let st: Box<dyn Any> = ts;
let debug = st.cast::<dyn Debug>();
assert!(debug.is_ok());
}
#[test]
fn cast_rc_from_any() {
let ts = Rc::new(TestStruct);
let st: Rc<dyn Any> = ts;
let debug = st.cast::<dyn Debug>();
assert!(debug.is_ok());
}
#[test]
fn cast_arc_from_any() {
let ts = Arc::new(TestStruct);
let st: Arc<dyn Any + Send + Sync> = ts;
let debug = st.cast::<dyn Debug>();
assert!(debug.is_ok());
}
#[test]
fn impls_ref() {
let ts = TestStruct;
let st: &dyn SourceTrait = &ts;
assert!(st.impls::<dyn Debug>());
}
#[test]
fn impls_mut() {
let mut ts = TestStruct;
let st: &mut dyn SourceTrait = &mut ts;
assert!((*st).impls::<dyn Debug>());
}
#[test]
fn impls_box() {
let ts = Box::new(TestStruct);
let st: Box<dyn SourceTrait> = ts;
assert!((*st).impls::<dyn Debug>());
}
#[test]
fn impls_rc() {
let ts = Rc::new(TestStruct);
let st: Rc<dyn SourceTrait> = ts;
assert!((*st).impls::<dyn Debug>());
}
#[test]
fn impls_arc() {
let ts = Arc::new(TestStruct);
let st: Arc<dyn SourceTrait> = ts;
assert!((*st).impls::<dyn Debug>());
}
#[test]
fn impls_not_ref() {
let ts = TestStruct;
let st: &dyn SourceTrait = &ts;
assert!(!st.impls::<dyn Display>());
}
#[test]
fn impls_not_mut() {
let mut ts = TestStruct;
let st: &mut dyn Any = &mut ts;
assert!(!(*st).impls::<dyn Display>());
}
#[test]
fn impls_not_box() {
let ts = Box::new(TestStruct);
let st: Box<dyn SourceTrait> = ts;
assert!(!st.impls::<dyn Display>());
}
#[test]
fn impls_not_rc() {
let ts = Rc::new(TestStruct);
let st: Rc<dyn SourceTrait> = ts;
assert!(!(*st).impls::<dyn Display>());
}
#[test]
fn impls_not_arc() {
let ts = Arc::new(TestStruct);
let st: Arc<dyn SourceTrait> = ts;
assert!(!(*st).impls::<dyn Display>());
}
}