use std::{ fmt::Debug, hash::{Hash, Hasher}, }; use std::{any::TypeId, marker::PhantomData}; use serde::{Serialize, Deserialize}; use uuid::Uuid; use bevy_property::{Properties, Property, AsProperties}; #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)] pub struct HandleId(pub Uuid); pub const DEFAULT_HANDLE_ID: HandleId = HandleId(Uuid::from_u128(240940089166493627844978703213080810552)); impl HandleId { pub fn new() -> HandleId { HandleId(Uuid::new_v4()) } } impl Property for HandleId { fn any(&self) -> &dyn std::any::Any { self } fn any_mut(&mut self) -> &mut dyn std::any::Any { self } fn clone_prop(&self) -> Box { Box::new(self.clone()) } fn set(&mut self, value: &dyn Property) { let value = value.any(); if let Some(prop) = value.downcast_ref::() { *self = *prop; } else { panic!("prop value is not {}", std::any::type_name::()); } } fn apply(&mut self, value: &dyn Property) { self.set(value); } } impl AsProperties for HandleId { fn as_properties(&self) -> Option<&dyn Properties> { None } } #[derive(Properties)] pub struct Handle where T: 'static { pub id: HandleId, #[prop(ignore)] marker: PhantomData, } impl Handle { pub fn new() -> Self { Handle { id: HandleId::new(), marker: PhantomData, } } pub const fn from_id(id: HandleId) -> Self { Handle { id, marker: PhantomData, } } pub const fn from_u128(value: u128) -> Self { Handle { id: HandleId(Uuid::from_u128(value)), marker: PhantomData, } } pub const fn from_bytes(bytes: [u8; 16]) -> Self { Handle { id: HandleId(Uuid::from_bytes(bytes)), marker: PhantomData, } } pub fn from_untyped(untyped_handle: HandleUntyped) -> Option> where T: 'static, { if TypeId::of::() == untyped_handle.type_id { Some(Handle::from_id(untyped_handle.id)) } else { None } } } impl From for Handle { fn from(value: HandleId) -> Self { Handle::from_id(value) } } impl From for Handle { fn from(value: u128) -> Self { Handle::from_u128(value) } } impl From<[u8; 16]> for Handle { fn from(value: [u8; 16]) -> Self { Handle::from_bytes(value) } } impl From for Handle where T: 'static, { fn from(handle: HandleUntyped) -> Self { if TypeId::of::() == handle.type_id { Handle { id: handle.id, marker: PhantomData::default(), } } else { panic!("attempted to convert untyped handle to incorrect typed handle") } } } impl Hash for Handle { fn hash(&self, state: &mut H) { self.id.hash(state); } } impl PartialEq for Handle { fn eq(&self, other: &Self) -> bool { self.id == other.id } } impl Eq for Handle {} impl Debug for Handle { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { let name = std::any::type_name::().split("::").last().unwrap(); write!(f, "Handle<{}>({:?})", name, self.id.0) } } impl Default for Handle { fn default() -> Self { Handle { id: DEFAULT_HANDLE_ID, marker: PhantomData, } } } impl Clone for Handle { fn clone(&self) -> Self { Handle { id: self.id.clone(), marker: PhantomData, } } } impl Copy for Handle {} // SAFE: T is phantom data and Handle::id is an integer unsafe impl Send for Handle {} unsafe impl Sync for Handle {} #[derive(Hash, Copy, Clone, Eq, PartialEq, Debug)] pub struct HandleUntyped { pub id: HandleId, pub type_id: TypeId, } impl HandleUntyped { pub fn is_handle(untyped: &HandleUntyped) -> bool { TypeId::of::() == untyped.type_id } } impl From> for HandleUntyped where T: 'static, { fn from(handle: Handle) -> Self { HandleUntyped { id: handle.id, type_id: TypeId::of::(), } } }