Skip to content

Commit d05c435

Browse files
authored
Replace Handle::Weak with Handle::Uuid. (#19896)
# Objective - Progress towards #19024. ## Solution - Remove `Handle::Weak`! If users were relying on `Handle::Weak` for some purpose, they can almost certainly replace it with raw `AssetId` instead. If they cannot, they can make their own enum that holds either a Handle or an AssetId. In either case, we don't need weak handles! Sadly we still need Uuid handles since we rely on them for "default" assets and "invalid" assets, as well as anywhere where a component wants to impl default with a non-defaulted asset handle. One step at a time though!
1 parent 1a410ef commit d05c435

File tree

17 files changed

+143
-127
lines changed

17 files changed

+143
-127
lines changed

crates/bevy_anti_aliasing/src/smaa/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
use bevy_app::{App, Plugin};
3333
#[cfg(feature = "smaa_luts")]
3434
use bevy_asset::load_internal_binary_asset;
35-
use bevy_asset::{embedded_asset, load_embedded_asset, weak_handle, Handle};
35+
use bevy_asset::{embedded_asset, load_embedded_asset, uuid_handle, Handle};
3636
#[cfg(not(feature = "smaa_luts"))]
3737
use bevy_core_pipeline::tonemapping::lut_placeholder;
3838
use bevy_core_pipeline::{
@@ -81,10 +81,10 @@ use bevy_utils::prelude::default;
8181

8282
/// The handle of the area LUT, a KTX2 format texture that SMAA uses internally.
8383
const SMAA_AREA_LUT_TEXTURE_HANDLE: Handle<Image> =
84-
weak_handle!("569c4d67-c7fa-4958-b1af-0836023603c0");
84+
uuid_handle!("569c4d67-c7fa-4958-b1af-0836023603c0");
8585
/// The handle of the search LUT, a KTX2 format texture that SMAA uses internally.
8686
const SMAA_SEARCH_LUT_TEXTURE_HANDLE: Handle<Image> =
87-
weak_handle!("43b97515-252e-4c8a-b9af-f2fc528a1c27");
87+
uuid_handle!("43b97515-252e-4c8a-b9af-f2fc528a1c27");
8888

8989
/// Adds support for subpixel morphological antialiasing, or SMAA.
9090
pub struct SmaaPlugin;

crates/bevy_asset/src/handle.rs

Lines changed: 66 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ use bevy_reflect::{std_traits::ReflectDefault, Reflect, TypePath};
77
use core::{
88
any::TypeId,
99
hash::{Hash, Hasher},
10+
marker::PhantomData,
1011
};
1112
use crossbeam_channel::{Receiver, Sender};
1213
use disqualified::ShortName;
1314
use thiserror::Error;
15+
use uuid::Uuid;
1416

1517
/// Provides [`Handle`] and [`UntypedHandle`] _for a specific asset type_.
1618
/// This should _only_ be used for one specific asset type.
@@ -117,7 +119,7 @@ impl core::fmt::Debug for StrongHandle {
117119
/// avoiding the need to store multiple copies of the same data.
118120
///
119121
/// If a [`Handle`] is [`Handle::Strong`], the [`Asset`] will be kept
120-
/// alive until the [`Handle`] is dropped. If a [`Handle`] is [`Handle::Weak`], it does not necessarily reference a live [`Asset`],
122+
/// alive until the [`Handle`] is dropped. If a [`Handle`] is [`Handle::Uuid`], it does not necessarily reference a live [`Asset`],
121123
/// nor will it keep assets alive.
122124
///
123125
/// Modifying a *handle* will change which existing asset is referenced, but modifying the *asset*
@@ -133,16 +135,16 @@ pub enum Handle<A: Asset> {
133135
/// A "strong" reference to a live (or loading) [`Asset`]. If a [`Handle`] is [`Handle::Strong`], the [`Asset`] will be kept
134136
/// alive until the [`Handle`] is dropped. Strong handles also provide access to additional asset metadata.
135137
Strong(Arc<StrongHandle>),
136-
/// A "weak" reference to an [`Asset`]. If a [`Handle`] is [`Handle::Weak`], it does not necessarily reference a live [`Asset`],
137-
/// nor will it keep assets alive.
138-
Weak(AssetId<A>),
138+
/// A reference to an [`Asset`] using a stable-across-runs / const identifier. Dropping this
139+
/// handle will not result in the asset being dropped.
140+
Uuid(Uuid, #[reflect(ignore, clone)] PhantomData<fn() -> A>),
139141
}
140142

141143
impl<T: Asset> Clone for Handle<T> {
142144
fn clone(&self) -> Self {
143145
match self {
144146
Handle::Strong(handle) => Handle::Strong(handle.clone()),
145-
Handle::Weak(id) => Handle::Weak(*id),
147+
Handle::Uuid(uuid, ..) => Handle::Uuid(*uuid, PhantomData),
146148
}
147149
}
148150
}
@@ -153,7 +155,7 @@ impl<A: Asset> Handle<A> {
153155
pub fn id(&self) -> AssetId<A> {
154156
match self {
155157
Handle::Strong(handle) => handle.id.typed_unchecked(),
156-
Handle::Weak(id) => *id,
158+
Handle::Uuid(uuid, ..) => AssetId::Uuid { uuid: *uuid },
157159
}
158160
}
159161

@@ -162,14 +164,14 @@ impl<A: Asset> Handle<A> {
162164
pub fn path(&self) -> Option<&AssetPath<'static>> {
163165
match self {
164166
Handle::Strong(handle) => handle.path.as_ref(),
165-
Handle::Weak(_) => None,
167+
Handle::Uuid(..) => None,
166168
}
167169
}
168170

169-
/// Returns `true` if this is a weak handle.
171+
/// Returns `true` if this is a uuid handle.
170172
#[inline]
171-
pub fn is_weak(&self) -> bool {
172-
matches!(self, Handle::Weak(_))
173+
pub fn is_uuid(&self) -> bool {
174+
matches!(self, Handle::Uuid(..))
173175
}
174176

175177
/// Returns `true` if this is a strong handle.
@@ -178,18 +180,9 @@ impl<A: Asset> Handle<A> {
178180
matches!(self, Handle::Strong(_))
179181
}
180182

181-
/// Creates a [`Handle::Weak`] clone of this [`Handle`], which will not keep the referenced [`Asset`] alive.
182-
#[inline]
183-
pub fn clone_weak(&self) -> Self {
184-
match self {
185-
Handle::Strong(handle) => Handle::Weak(handle.id.typed_unchecked::<A>()),
186-
Handle::Weak(id) => Handle::Weak(*id),
187-
}
188-
}
189-
190183
/// Converts this [`Handle`] to an "untyped" / "generic-less" [`UntypedHandle`], which stores the [`Asset`] type information
191-
/// _inside_ [`UntypedHandle`]. This will return [`UntypedHandle::Strong`] for [`Handle::Strong`] and [`UntypedHandle::Weak`] for
192-
/// [`Handle::Weak`].
184+
/// _inside_ [`UntypedHandle`]. This will return [`UntypedHandle::Strong`] for [`Handle::Strong`] and [`UntypedHandle::Uuid`] for
185+
/// [`Handle::Uuid`].
193186
#[inline]
194187
pub fn untyped(self) -> UntypedHandle {
195188
self.into()
@@ -198,7 +191,7 @@ impl<A: Asset> Handle<A> {
198191

199192
impl<A: Asset> Default for Handle<A> {
200193
fn default() -> Self {
201-
Handle::Weak(AssetId::default())
194+
Handle::Uuid(AssetId::<A>::DEFAULT_UUID, PhantomData)
202195
}
203196
}
204197

@@ -214,7 +207,7 @@ impl<A: Asset> core::fmt::Debug for Handle<A> {
214207
handle.path
215208
)
216209
}
217-
Handle::Weak(id) => write!(f, "WeakHandle<{name}>({:?})", id.internal()),
210+
Handle::Uuid(uuid, ..) => write!(f, "UuidHandle<{name}>({uuid:?})"),
218211
}
219212
}
220213
}
@@ -284,8 +277,13 @@ impl<A: Asset> From<&mut Handle<A>> for UntypedAssetId {
284277
pub enum UntypedHandle {
285278
/// A strong handle, which will keep the referenced [`Asset`] alive until all strong handles are dropped.
286279
Strong(Arc<StrongHandle>),
287-
/// A weak handle, which does not keep the referenced [`Asset`] alive.
288-
Weak(UntypedAssetId),
280+
/// A UUID handle, which does not keep the referenced [`Asset`] alive.
281+
Uuid {
282+
/// An identifier that records the underlying asset type.
283+
type_id: TypeId,
284+
/// The UUID provided during asset registration.
285+
uuid: Uuid,
286+
},
289287
}
290288

291289
impl UntypedHandle {
@@ -294,7 +292,10 @@ impl UntypedHandle {
294292
pub fn id(&self) -> UntypedAssetId {
295293
match self {
296294
UntypedHandle::Strong(handle) => handle.id,
297-
UntypedHandle::Weak(id) => *id,
295+
UntypedHandle::Uuid { type_id, uuid } => UntypedAssetId::Uuid {
296+
uuid: *uuid,
297+
type_id: *type_id,
298+
},
298299
}
299300
}
300301

@@ -303,16 +304,7 @@ impl UntypedHandle {
303304
pub fn path(&self) -> Option<&AssetPath<'static>> {
304305
match self {
305306
UntypedHandle::Strong(handle) => handle.path.as_ref(),
306-
UntypedHandle::Weak(_) => None,
307-
}
308-
}
309-
310-
/// Creates an [`UntypedHandle::Weak`] clone of this [`UntypedHandle`], which will not keep the referenced [`Asset`] alive.
311-
#[inline]
312-
pub fn clone_weak(&self) -> UntypedHandle {
313-
match self {
314-
UntypedHandle::Strong(handle) => UntypedHandle::Weak(handle.id),
315-
UntypedHandle::Weak(id) => UntypedHandle::Weak(*id),
307+
UntypedHandle::Uuid { .. } => None,
316308
}
317309
}
318310

@@ -321,7 +313,7 @@ impl UntypedHandle {
321313
pub fn type_id(&self) -> TypeId {
322314
match self {
323315
UntypedHandle::Strong(handle) => handle.id.type_id(),
324-
UntypedHandle::Weak(id) => id.type_id(),
316+
UntypedHandle::Uuid { type_id, .. } => *type_id,
325317
}
326318
}
327319

@@ -330,7 +322,7 @@ impl UntypedHandle {
330322
pub fn typed_unchecked<A: Asset>(self) -> Handle<A> {
331323
match self {
332324
UntypedHandle::Strong(handle) => Handle::Strong(handle),
333-
UntypedHandle::Weak(id) => Handle::Weak(id.typed_unchecked::<A>()),
325+
UntypedHandle::Uuid { uuid, .. } => Handle::Uuid(uuid, PhantomData),
334326
}
335327
}
336328

@@ -345,10 +337,7 @@ impl UntypedHandle {
345337
TypeId::of::<A>(),
346338
"The target Handle<A>'s TypeId does not match the TypeId of this UntypedHandle"
347339
);
348-
match self {
349-
UntypedHandle::Strong(handle) => Handle::Strong(handle),
350-
UntypedHandle::Weak(id) => Handle::Weak(id.typed_unchecked::<A>()),
351-
}
340+
self.typed_unchecked()
352341
}
353342

354343
/// Converts to a typed Handle. This will panic if the internal [`TypeId`] does not match the given asset type `A`
@@ -376,7 +365,7 @@ impl UntypedHandle {
376365
pub fn meta_transform(&self) -> Option<&MetaTransform> {
377366
match self {
378367
UntypedHandle::Strong(handle) => handle.meta_transform.as_ref(),
379-
UntypedHandle::Weak(_) => None,
368+
UntypedHandle::Uuid { .. } => None,
380369
}
381370
}
382371
}
@@ -409,12 +398,9 @@ impl core::fmt::Debug for UntypedHandle {
409398
handle.path
410399
)
411400
}
412-
UntypedHandle::Weak(id) => write!(
413-
f,
414-
"WeakHandle{{ type_id: {:?}, id: {:?} }}",
415-
id.type_id(),
416-
id.internal()
417-
),
401+
UntypedHandle::Uuid { type_id, uuid } => {
402+
write!(f, "UuidHandle{{ type_id: {type_id:?}, uuid: {uuid:?} }}",)
403+
}
418404
}
419405
}
420406
}
@@ -474,7 +460,10 @@ impl<A: Asset> From<Handle<A>> for UntypedHandle {
474460
fn from(value: Handle<A>) -> Self {
475461
match value {
476462
Handle::Strong(handle) => UntypedHandle::Strong(handle),
477-
Handle::Weak(id) => UntypedHandle::Weak(id.into()),
463+
Handle::Uuid(uuid, _) => UntypedHandle::Uuid {
464+
type_id: TypeId::of::<A>(),
465+
uuid,
466+
},
478467
}
479468
}
480469
}
@@ -490,36 +479,37 @@ impl<A: Asset> TryFrom<UntypedHandle> for Handle<A> {
490479
return Err(UntypedAssetConversionError::TypeIdMismatch { expected, found });
491480
}
492481

493-
match value {
494-
UntypedHandle::Strong(handle) => Ok(Handle::Strong(handle)),
495-
UntypedHandle::Weak(id) => {
496-
let Ok(id) = id.try_into() else {
497-
return Err(UntypedAssetConversionError::TypeIdMismatch { expected, found });
498-
};
499-
Ok(Handle::Weak(id))
500-
}
501-
}
482+
Ok(match value {
483+
UntypedHandle::Strong(handle) => Handle::Strong(handle),
484+
UntypedHandle::Uuid { uuid, .. } => Handle::Uuid(uuid, PhantomData),
485+
})
502486
}
503487
}
504488

505-
/// Creates a weak [`Handle`] from a string literal containing a UUID.
489+
/// Creates a [`Handle`] from a string literal containing a UUID.
506490
///
507491
/// # Examples
508492
///
509493
/// ```
510-
/// # use bevy_asset::{Handle, weak_handle};
494+
/// # use bevy_asset::{Handle, uuid_handle};
511495
/// # type Shader = ();
512-
/// const SHADER: Handle<Shader> = weak_handle!("1347c9b7-c46a-48e7-b7b8-023a354b7cac");
496+
/// const SHADER: Handle<Shader> = uuid_handle!("1347c9b7-c46a-48e7-b7b8-023a354b7cac");
513497
/// ```
514498
#[macro_export]
515-
macro_rules! weak_handle {
499+
macro_rules! uuid_handle {
516500
($uuid:expr) => {{
517-
$crate::Handle::Weak($crate::AssetId::Uuid {
518-
uuid: $crate::uuid::uuid!($uuid),
519-
})
501+
$crate::Handle::Uuid($crate::uuid::uuid!($uuid), core::marker::PhantomData)
520502
}};
521503
}
522504

505+
#[deprecated = "Use uuid_handle! instead"]
506+
#[macro_export]
507+
macro_rules! weak_handle {
508+
($uuid:expr) => {
509+
uuid_handle!($uuid)
510+
};
511+
}
512+
523513
/// Errors preventing the conversion of to/from an [`UntypedHandle`] and a [`Handle`].
524514
#[derive(Error, Debug, PartialEq, Clone)]
525515
#[non_exhaustive]
@@ -559,15 +549,12 @@ mod tests {
559549
/// Typed and Untyped `Handles` should be equivalent to each other and themselves
560550
#[test]
561551
fn equality() {
562-
let typed = AssetId::<TestAsset>::Uuid { uuid: UUID_1 };
563-
let untyped = UntypedAssetId::Uuid {
552+
let typed = Handle::<TestAsset>::Uuid(UUID_1, PhantomData);
553+
let untyped = UntypedHandle::Uuid {
564554
type_id: TypeId::of::<TestAsset>(),
565555
uuid: UUID_1,
566556
};
567557

568-
let typed = Handle::Weak(typed);
569-
let untyped = UntypedHandle::Weak(untyped);
570-
571558
assert_eq!(
572559
Ok(typed.clone()),
573560
Handle::<TestAsset>::try_from(untyped.clone())
@@ -585,22 +572,17 @@ mod tests {
585572
fn ordering() {
586573
assert!(UUID_1 < UUID_2);
587574

588-
let typed_1 = AssetId::<TestAsset>::Uuid { uuid: UUID_1 };
589-
let typed_2 = AssetId::<TestAsset>::Uuid { uuid: UUID_2 };
590-
let untyped_1 = UntypedAssetId::Uuid {
575+
let typed_1 = Handle::<TestAsset>::Uuid(UUID_1, PhantomData);
576+
let typed_2 = Handle::<TestAsset>::Uuid(UUID_2, PhantomData);
577+
let untyped_1 = UntypedHandle::Uuid {
591578
type_id: TypeId::of::<TestAsset>(),
592579
uuid: UUID_1,
593580
};
594-
let untyped_2 = UntypedAssetId::Uuid {
581+
let untyped_2 = UntypedHandle::Uuid {
595582
type_id: TypeId::of::<TestAsset>(),
596583
uuid: UUID_2,
597584
};
598585

599-
let typed_1 = Handle::Weak(typed_1);
600-
let typed_2 = Handle::Weak(typed_2);
601-
let untyped_1 = UntypedHandle::Weak(untyped_1);
602-
let untyped_2 = UntypedHandle::Weak(untyped_2);
603-
604586
assert!(typed_1 < typed_2);
605587
assert!(untyped_1 < untyped_2);
606588

@@ -617,15 +599,12 @@ mod tests {
617599
/// Typed and Untyped `Handles` should be equivalently hashable to each other and themselves
618600
#[test]
619601
fn hashing() {
620-
let typed = AssetId::<TestAsset>::Uuid { uuid: UUID_1 };
621-
let untyped = UntypedAssetId::Uuid {
602+
let typed = Handle::<TestAsset>::Uuid(UUID_1, PhantomData);
603+
let untyped = UntypedHandle::Uuid {
622604
type_id: TypeId::of::<TestAsset>(),
623605
uuid: UUID_1,
624606
};
625607

626-
let typed = Handle::Weak(typed);
627-
let untyped = UntypedHandle::Weak(untyped);
628-
629608
assert_eq!(
630609
hash(&typed),
631610
hash(&Handle::<TestAsset>::try_from(untyped.clone()).unwrap())
@@ -637,15 +616,12 @@ mod tests {
637616
/// Typed and Untyped `Handles` should be interchangeable
638617
#[test]
639618
fn conversion() {
640-
let typed = AssetId::<TestAsset>::Uuid { uuid: UUID_1 };
641-
let untyped = UntypedAssetId::Uuid {
619+
let typed = Handle::<TestAsset>::Uuid(UUID_1, PhantomData);
620+
let untyped = UntypedHandle::Uuid {
642621
type_id: TypeId::of::<TestAsset>(),
643622
uuid: UUID_1,
644623
};
645624

646-
let typed = Handle::Weak(typed);
647-
let untyped = UntypedHandle::Weak(untyped);
648-
649625
assert_eq!(typed, Handle::try_from(untyped.clone()).unwrap());
650626
assert_eq!(UntypedHandle::from(typed.clone()), untyped);
651627
}

crates/bevy_core_pipeline/src/experimental/mip_generation/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::core_3d::{
1212
prepare_core_3d_depth_textures,
1313
};
1414
use bevy_app::{App, Plugin};
15-
use bevy_asset::{load_internal_asset, weak_handle, Handle};
15+
use bevy_asset::{load_internal_asset, uuid_handle, Handle};
1616
use bevy_derive::{Deref, DerefMut};
1717
use bevy_ecs::{
1818
component::Component,
@@ -51,7 +51,7 @@ use tracing::debug;
5151

5252
/// Identifies the `downsample_depth.wgsl` shader.
5353
pub const DOWNSAMPLE_DEPTH_SHADER_HANDLE: Handle<Shader> =
54-
weak_handle!("a09a149e-5922-4fa4-9170-3c1a13065364");
54+
uuid_handle!("a09a149e-5922-4fa4-9170-3c1a13065364");
5555

5656
/// The maximum number of mip levels that we can produce.
5757
///

0 commit comments

Comments
 (0)