use std::{
any::{Any, TypeId},
ops::Deref,
};
mod handle;
mod impls;
mod printer;
pub use {handle::*, printer::*};
use bevy_ecs::{
component::{ComponentId, ComponentInfo},
reflect::AppTypeRegistry,
world::World,
};
use bevy_reflect::{TypeData, TypeInfo, TypeRegistry, reflect_trait};
pub trait GetTypeInfo {
fn get_type_info(&self, type_id: TypeId) -> Option<&TypeInfo>;
fn query_type_registration(
&self,
type_id: TypeId,
type_data_id: TypeId,
) -> Option<Box<dyn TypeData>>;
fn get_component_info(&self, component_id: ComponentId) -> Option<&ComponentInfo>;
unsafe fn as_any_static(&self) -> &dyn Any;
}
pub trait GetTypeInfoExtensions<'s> {
fn get_type_data<T: TypeData + 'static>(&'s self, type_id: TypeId) -> Option<T>;
}
impl<'s> GetTypeInfoExtensions<'s> for &'s dyn GetTypeInfo {
fn get_type_data<T: TypeData + 'static>(&'s self, type_id: TypeId) -> Option<T> {
self.query_type_registration(type_id, std::any::TypeId::of::<T>())
.and_then(|t| t.downcast().ok())
.map(|b| *b)
}
}
impl GetTypeInfo for TypeRegistry {
fn get_type_info(&self, type_id: TypeId) -> Option<&TypeInfo> {
self.get(type_id)
.map(|registration| registration.type_info())
}
fn query_type_registration(
&self,
type_id: TypeId,
type_data_id: TypeId,
) -> Option<Box<dyn TypeData>> {
self.get(type_id)
.and_then(|r| r.data_by_id(type_data_id).map(|t| t.clone_type_data()))
}
fn get_component_info(&self, _component_id: ComponentId) -> Option<&ComponentInfo> {
None
}
unsafe fn as_any_static(&self) -> &dyn Any {
self
}
}
impl GetTypeInfo for World {
fn get_type_info(&self, type_id: TypeId) -> Option<&TypeInfo> {
self.get_resource::<AppTypeRegistry>()
.and_then(|r| r.read().get_type_info(type_id))
}
fn query_type_registration(
&self,
type_id: TypeId,
type_data_id: TypeId,
) -> Option<Box<dyn TypeData>> {
self.get_resource::<AppTypeRegistry>().and_then(|r| {
r.read()
.get(type_id)
.and_then(|r| r.data_by_id(type_data_id).map(|t| t.clone_type_data()))
})
}
fn get_component_info(&self, component_id: ComponentId) -> Option<&ComponentInfo> {
self.components().get_info(component_id)
}
unsafe fn as_any_static(&self) -> &dyn Any {
self
}
}
#[reflect_trait]
pub trait DisplayWithTypeInfo {
fn display_with_type_info(
&self,
f: &mut std::fmt::Formatter<'_>,
type_info_provider: Option<&dyn GetTypeInfo>,
) -> std::fmt::Result;
}
impl<T: DisplayWithTypeInfo> DisplayWithTypeInfo for WithTypeInfo<'_, T> {
fn display_with_type_info(
&self,
f: &mut std::fmt::Formatter<'_>,
type_info_provider: Option<&dyn GetTypeInfo>,
) -> std::fmt::Result {
self.0.display_with_type_info(f, type_info_provider)
}
}
impl<T: DisplayWithTypeInfo> std::fmt::Display for WithTypeInfo<'_, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let provider = self.1.or_else(|| {
GLOBAL_TYPE_INFO_PROVIDER
.get()
.and_then(|get_provider| get_provider())
});
self.0.display_with_type_info(f, provider)
}
}
pub trait DebugWithTypeInfo {
fn to_string_with_type_info(
&self,
f: &mut std::fmt::Formatter<'_>,
type_info_provider: Option<&dyn GetTypeInfo>,
) -> std::fmt::Result;
}
pub static GLOBAL_TYPE_INFO_PROVIDER: std::sync::OnceLock<
fn() -> Option<&'static dyn GetTypeInfo>,
> = std::sync::OnceLock::new();
pub struct WithTypeInfo<'a, T: ?Sized>(&'a T, Option<&'a dyn GetTypeInfo>);
impl<'a, T: ?Sized> WithTypeInfo<'a, T> {
pub fn new(value: &'a T) -> Self {
Self(value, None)
}
pub fn new_with_info(value: &'a T, provider: &'a dyn GetTypeInfo) -> Self {
Self(value, Some(provider))
}
pub fn new_with_opt_info(value: &'a T, provider: Option<&'a dyn GetTypeInfo>) -> Self {
Self(value, provider)
}
}
impl<T: DebugWithTypeInfo + ?Sized> Deref for WithTypeInfo<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.0
}
}
impl<'a, T: DebugWithTypeInfo + ?Sized> std::fmt::Debug for WithTypeInfo<'a, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let provider = self.1.or_else(|| {
GLOBAL_TYPE_INFO_PROVIDER
.get()
.and_then(|get_provider| get_provider())
});
self.0.to_string_with_type_info(f, provider)
}
}
impl<T: DebugWithTypeInfo + ?Sized> DebugWithTypeInfo for WithTypeInfo<'_, T> {
fn to_string_with_type_info(
&self,
f: &mut std::fmt::Formatter<'_>,
type_info_provider: Option<&dyn GetTypeInfo>,
) -> std::fmt::Result {
self.0.to_string_with_type_info(f, type_info_provider)
}
}
struct FakeType;
pub trait OrFakeId {
fn or_fake_id(&self) -> TypeId;
fn fake_id() -> TypeId {
TypeId::of::<FakeType>()
}
}
impl OrFakeId for Option<TypeId> {
fn or_fake_id(&self) -> TypeId {
self.unwrap_or_else(TypeId::of::<FakeType>)
}
}
trait SelfBuilder: Sized {
fn build_with<F: FnOnce(Self) -> Self>(self, f: F) -> Self;
}
impl<T: Sized> SelfBuilder for T {
fn build_with<F: FnOnce(Self) -> Self>(self, f: F) -> Self {
f(self)
}
}
pub struct DebugStruct<'a, 'b: 'a, 't> {
builder: std::fmt::DebugStruct<'a, 'b>,
type_info: Option<&'t dyn GetTypeInfo>,
}
impl<'a, 'b: 'a, 't> DebugStruct<'a, 'b, 't> {
pub fn new(
f: &'a mut std::fmt::Formatter<'b>,
name: &str,
type_info: Option<&'t dyn GetTypeInfo>,
) -> Self {
Self {
builder: f.debug_struct(name),
type_info,
}
}
pub fn field(&mut self, name: &str, value: &dyn DebugWithTypeInfo) -> &mut Self {
self.builder.field(
name,
&WithTypeInfo::new_with_opt_info(value, self.type_info),
);
self
}
pub fn finish(&mut self) -> std::fmt::Result {
self.builder.finish()
}
}
pub struct DebugTuple<'a, 'b: 'a, 't> {
builder: std::fmt::DebugTuple<'a, 'b>,
type_info: Option<&'t dyn GetTypeInfo>,
}
impl<'a, 'b: 'a, 't> DebugTuple<'a, 'b, 't> {
pub fn new(
f: &'a mut std::fmt::Formatter<'b>,
name: &str,
type_info: Option<&'t dyn GetTypeInfo>,
) -> Self {
Self {
builder: f.debug_tuple(name),
type_info,
}
}
pub fn field(&mut self, value: &dyn DebugWithTypeInfo) -> &mut Self {
self.builder
.field(&WithTypeInfo::new_with_opt_info(value, self.type_info));
self
}
pub fn finish(&mut self) -> std::fmt::Result {
self.builder.finish()
}
}
pub struct DebugList<'a, 'b: 'a, 't> {
builder: std::fmt::DebugList<'a, 'b>,
type_info: Option<&'t dyn GetTypeInfo>,
}
impl<'a, 'b: 'a, 't> DebugList<'a, 'b, 't> {
pub fn new(f: &'a mut std::fmt::Formatter<'b>, type_info: Option<&'t dyn GetTypeInfo>) -> Self {
Self {
builder: f.debug_list(),
type_info,
}
}
pub fn entry(&mut self, value: &dyn DebugWithTypeInfo) -> &mut Self {
self.builder
.entry(&WithTypeInfo::new_with_opt_info(value, self.type_info));
self
}
pub fn entries<I: IntoIterator<Item = &'a dyn DebugWithTypeInfo>>(
&mut self,
values: I,
) -> &mut Self {
for value in values {
self.builder
.entry(&WithTypeInfo::new_with_opt_info(value, self.type_info));
}
self
}
pub fn finish(&mut self) -> std::fmt::Result {
self.builder.finish()
}
}
pub struct DebugSet<'a, 'b: 'a, 't> {
builder: std::fmt::DebugSet<'a, 'b>,
type_info: Option<&'t dyn GetTypeInfo>,
}
impl<'a, 'b: 'a, 't> DebugSet<'a, 'b, 't> {
pub fn new(f: &'a mut std::fmt::Formatter<'b>, type_info: Option<&'t dyn GetTypeInfo>) -> Self {
Self {
builder: f.debug_set(),
type_info,
}
}
pub fn entry(&mut self, value: &dyn DebugWithTypeInfo) -> &mut Self {
self.builder
.entry(&WithTypeInfo::new_with_opt_info(value, self.type_info));
self
}
pub fn entries<I: IntoIterator<Item = &'a dyn DebugWithTypeInfo>>(
&mut self,
values: I,
) -> &mut Self {
for value in values {
self.builder
.entry(&WithTypeInfo::new_with_opt_info(value, self.type_info));
}
self
}
pub fn finish(&mut self) -> std::fmt::Result {
self.builder.finish()
}
}
pub struct DebugMap<'a, 'b: 'a, 't> {
builder: std::fmt::DebugMap<'a, 'b>,
type_info: Option<&'t dyn GetTypeInfo>,
}
impl<'a, 'b: 'a, 't> DebugMap<'a, 'b, 't> {
pub fn new(f: &'a mut std::fmt::Formatter<'b>, type_info: Option<&'t dyn GetTypeInfo>) -> Self {
Self {
builder: f.debug_map(),
type_info,
}
}
pub fn entry(
&mut self,
key: &dyn DebugWithTypeInfo,
value: &dyn DebugWithTypeInfo,
) -> &mut Self {
self.builder.entry(
&WithTypeInfo::new_with_opt_info(key, self.type_info),
&WithTypeInfo::new_with_opt_info(value, self.type_info),
);
self
}
pub fn entries<
I: IntoIterator<Item = (&'a dyn DebugWithTypeInfo, &'a dyn DebugWithTypeInfo)>,
>(
&mut self,
values: I,
) -> &mut Self {
for (key, value) in values {
self.builder.entry(
&WithTypeInfo::new_with_opt_info(key, self.type_info),
&WithTypeInfo::new_with_opt_info(value, self.type_info),
);
}
self
}
pub fn key(&mut self, key: &dyn DebugWithTypeInfo) -> &mut Self {
self.builder
.key(&WithTypeInfo::new_with_opt_info(key, self.type_info));
self
}
pub fn value(&mut self, value: &dyn DebugWithTypeInfo) -> &mut Self {
self.builder
.value(&WithTypeInfo::new_with_opt_info(value, self.type_info));
self
}
pub fn finish(&mut self) -> std::fmt::Result {
self.builder.finish()
}
}
pub trait DebugWithTypeInfoBuilder<'a, 'b: 'a, 't> {
fn debug_struct_with_type_info(
&'a mut self,
name: &str,
type_info: Option<&'t dyn GetTypeInfo>,
) -> DebugStruct<'a, 'b, 't>;
fn debug_tuple_with_type_info(
&'a mut self,
name: &str,
type_info: Option<&'t dyn GetTypeInfo>,
) -> DebugTuple<'a, 'b, 't>;
fn debug_list_with_type_info(
&'a mut self,
type_info: Option<&'t dyn GetTypeInfo>,
) -> DebugList<'a, 'b, 't>;
fn debug_set_with_type_info(
&'a mut self,
type_info: Option<&'t dyn GetTypeInfo>,
) -> DebugSet<'a, 'b, 't>;
fn debug_map_with_type_info(
&'a mut self,
type_info: Option<&'t dyn GetTypeInfo>,
) -> DebugMap<'a, 'b, 't>;
}
impl<'a, 'b: 'a, 't> DebugWithTypeInfoBuilder<'a, 'b, 't> for std::fmt::Formatter<'b> {
fn debug_struct_with_type_info(
&'a mut self,
name: &str,
type_info: Option<&'t dyn GetTypeInfo>,
) -> DebugStruct<'a, 'b, 't> {
DebugStruct::new(self, name, type_info)
}
fn debug_tuple_with_type_info(
&'a mut self,
name: &str,
type_info: Option<&'t dyn GetTypeInfo>,
) -> DebugTuple<'a, 'b, 't> {
DebugTuple::new(self, name, type_info)
}
fn debug_list_with_type_info(
&'a mut self,
type_info: Option<&'t dyn GetTypeInfo>,
) -> DebugList<'a, 'b, 't> {
DebugList::new(self, type_info)
}
fn debug_set_with_type_info(
&'a mut self,
type_info: Option<&'t dyn GetTypeInfo>,
) -> DebugSet<'a, 'b, 't> {
DebugSet::new(self, type_info)
}
fn debug_map_with_type_info(
&'a mut self,
type_info: Option<&'t dyn GetTypeInfo>,
) -> DebugMap<'a, 'b, 't> {
DebugMap::new(self, type_info)
}
}
macro_rules! impl_debug_with_type_info_via_debug {
($t:ty) => {
impl $crate::DebugWithTypeInfo for $t {
fn to_string_with_type_info(
&self,
f: &mut std::fmt::Formatter<'_>,
_type_info_provider: Option<&dyn $crate::GetTypeInfo>,
) -> std::fmt::Result {
std::fmt::Debug::fmt(self, f)
}
}
};
}
macro_rules! impl_debug_with_type_info_via_display {
($($t:ty),*) => {
$(
impl DebugWithTypeInfo for $t {
fn to_string_with_type_info(
&self,
f: &mut std::fmt::Formatter<'_>,
_type_info_provider: Option<&dyn GetTypeInfo>,
) -> std::fmt::Result {
<Self as std::fmt::Display>::fmt(self, f)
}
}
)*
};
}
use impl_debug_with_type_info_via_debug;
use impl_debug_with_type_info_via_display;
macro_rules! impl_display_with_type_info_via_display {
($($t:ty),*) => {
$(
impl DisplayWithTypeInfo for $t {
fn display_with_type_info(
&self,
f: &mut std::fmt::Formatter<'_>,
_type_info_provider: Option<&dyn GetTypeInfo>,
) -> std::fmt::Result {
<Self as std::fmt::Display>::fmt(self, f)
}
}
)*
};
}
use impl_display_with_type_info_via_display;