bevy/crates/bevy_asset/src/handle.rs

191 lines
4.6 KiB
Rust
Raw Normal View History

use std::{
fmt::Debug,
hash::{Hash, Hasher},
};
2020-05-26 01:20:36 +00:00
use bevy_property::{Properties, Property};
use serde::{Deserialize, Serialize};
use std::{any::TypeId, marker::PhantomData};
use uuid::Uuid;
/// The ID of the "default" asset
pub(crate) const DEFAULT_HANDLE_ID: HandleId =
HandleId(Uuid::from_u128(240940089166493627844978703213080810552));
/// A unique id that corresponds to a specific asset in the [Assets](crate::Assets) collection.
2020-05-27 02:47:33 +00:00
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, Property)]
2020-05-03 19:35:07 +00:00
pub struct HandleId(pub Uuid);
impl HandleId {
pub fn new() -> HandleId {
HandleId(Uuid::new_v4())
}
}
/// A handle into a specific Asset of type `T`
///
/// Handles contain a unique id that corresponds to a specific asset in the [Assets](crate::Assets) collection.
#[derive(Properties)]
2020-05-26 01:20:36 +00:00
pub struct Handle<T>
where
T: 'static,
{
pub id: HandleId,
#[property(ignore)]
marker: PhantomData<T>,
}
impl<T> Handle<T> {
pub fn new() -> Self {
Handle {
id: HandleId::new(),
marker: PhantomData,
}
}
/// Gets a handle for the given type that has this handle's id. This is useful when an
/// asset is derived from another asset. In this case, a common handle can be used to
/// correlate them.
/// NOTE: This pattern might eventually be replaced by a more formal asset dependency system.
2020-06-17 05:23:33 +00:00
pub fn as_handle<U>(&self) -> Handle<U> {
Handle::from_id(self.id)
}
pub const fn from_id(id: HandleId) -> Self {
Handle {
id,
marker: PhantomData,
}
}
2020-05-04 18:20:12 +00:00
pub const fn from_u128(value: u128) -> Self {
Handle {
id: HandleId(Uuid::from_u128(value)),
marker: PhantomData,
}
}
2020-05-03 19:35:07 +00:00
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<Handle<T>>
where
T: 'static,
{
if TypeId::of::<T>() == untyped_handle.type_id {
Some(Handle::from_id(untyped_handle.id))
} else {
None
}
}
}
impl<T> From<HandleId> for Handle<T> {
fn from(value: HandleId) -> Self {
Handle::from_id(value)
}
}
impl<T> From<u128> for Handle<T> {
fn from(value: u128) -> Self {
Handle::from_u128(value)
}
}
impl<T> From<[u8; 16]> for Handle<T> {
fn from(value: [u8; 16]) -> Self {
Handle::from_bytes(value)
}
}
impl<T> From<HandleUntyped> for Handle<T>
where
T: 'static,
{
fn from(handle: HandleUntyped) -> Self {
if TypeId::of::<T>() == handle.type_id {
Handle {
id: handle.id,
marker: PhantomData::default(),
}
} else {
panic!("attempted to convert untyped handle to incorrect typed handle")
}
}
}
impl<T> Hash for Handle<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
}
}
impl<T> PartialEq for Handle<T> {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl<T> Eq for Handle<T> {}
impl<T> Debug for Handle<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
let name = std::any::type_name::<T>().split("::").last().unwrap();
write!(f, "Handle<{}>({:?})", name, self.id.0)
}
}
impl<T> Default for Handle<T> {
fn default() -> Self {
Handle {
id: DEFAULT_HANDLE_ID,
marker: PhantomData,
}
}
}
impl<T> Clone for Handle<T> {
fn clone(&self) -> Self {
Handle {
id: self.id.clone(),
marker: PhantomData,
}
}
}
impl<T> Copy for Handle<T> {}
// SAFE: T is phantom data and Handle::id is an integer
unsafe impl<T> Send for Handle<T> {}
unsafe impl<T> Sync for Handle<T> {}
/// A non-generic version of [Handle]
///
/// This allows handles to be mingled in a cross asset context. For example, storing `Handle<A>` and `Handle<B>` in the same `HashSet<HandleUntyped>`.
#[derive(Hash, Copy, Clone, Eq, PartialEq, Debug)]
pub struct HandleUntyped {
pub id: HandleId,
pub type_id: TypeId,
}
impl HandleUntyped {
pub fn is_handle<T: 'static>(untyped: &HandleUntyped) -> bool {
TypeId::of::<T>() == untyped.type_id
}
}
impl<T> From<Handle<T>> for HandleUntyped
where
T: 'static,
{
fn from(handle: Handle<T>) -> Self {
HandleUntyped {
id: handle.id,
type_id: TypeId::of::<T>(),
}
}
2020-05-16 07:27:30 +00:00
}