Generalized Into<AssetSourceId> and Into<AssetPath> Implementations over Lifetime (#10823)
				
					
				
			# Objective - Fixes #10478 ## Solution Generalised `From/Into` implementations over `&str` and `Option<&str>` for `AssetSourceId` and `AssetPath` across all lifetimes, not just static. To maintain access to the `'static`-only specialisation, these types (and `CowArc`) now include an `as_static` method which will apply the specialisation. ```rust // Snipped from `AssetApp` fn register_asset_source( &mut self, id: impl Into<AssetSourceId<'static>>, // ^^^^^^^ // | as_static is only available for 'static lifetimes source: AssetSourceBuilder, ) -> &mut Self { let id = id.into().as_static(); // ^^^^^^ ^^^^^^^^^ // | | Specialized (internally storing CowArc::Static) // | Generic Into (internally storing CowArc::Borrowed) // ... } ``` This post-fix specialisation is available here because the actual specialisation performed is only a marker for if/when modification or ownership is required, making the transform a very cheap operation. For cleanliness, I've also added `from_static`, which wraps this behaviour in a clean shorthand designed to replace `from` calls. --- ## Changelog - Generalised the following implementations over a generic lifetime: - `From<&'static str> for AssetSourceId<'static>` - `From<Option<&'static str>> for AssetSourceId<'static>` - `From<&'static str> for AssetPath<'static>` - `From<&'static Path> for AssetPath<'static>` - Added `as_static` specialisation to: - `CowArc` - `AssetSourceId` - `AssetPath` - Added `from_static` specialised constructor to: - `AssetSourceId` - `AssetPath` ## Migration Guide In areas where these implementations where being used, you can now add `from_static` in order to get the original specialised implementation which avoids creating an `Arc` internally. ```rust // Before let asset_path = AssetPath::from("my/path/to/an/asset.ext"); // After let asset_path = AssetPath::from_static("my/path/to/an/asset.ext"); ``` To be clear, this is only required if you wish to maintain the performance benefit that came with the specialisation. Existing code is _not_ broken by this change.
This commit is contained in:
		
							parent
							
								
									035fb78d6c
								
							
						
					
					
						commit
						491aec8e5b
					
				| @ -70,9 +70,26 @@ impl<'a> AssetSourceId<'a> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl From<&'static str> for AssetSourceId<'static> { | impl AssetSourceId<'static> { | ||||||
|     fn from(value: &'static str) -> Self { |     /// Indicates this [`AssetSourceId`] should have a static lifetime.
 | ||||||
|         AssetSourceId::Name(value.into()) |     #[inline] | ||||||
|  |     pub fn as_static(self) -> Self { | ||||||
|  |         match self { | ||||||
|  |             Self::Default => Self::Default, | ||||||
|  |             Self::Name(value) => Self::Name(value.as_static()), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Constructs an [`AssetSourceId`] with a static lifetime.
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn from_static(value: impl Into<Self>) -> Self { | ||||||
|  |         value.into().as_static() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<'a> From<&'a str> for AssetSourceId<'a> { | ||||||
|  |     fn from(value: &'a str) -> Self { | ||||||
|  |         AssetSourceId::Name(CowArc::Borrowed(value)) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -82,10 +99,10 @@ impl<'a, 'b> From<&'a AssetSourceId<'b>> for AssetSourceId<'b> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl From<Option<&'static str>> for AssetSourceId<'static> { | impl<'a> From<Option<&'a str>> for AssetSourceId<'a> { | ||||||
|     fn from(value: Option<&'static str>) -> Self { |     fn from(value: Option<&'a str>) -> Self { | ||||||
|         match value { |         match value { | ||||||
|             Some(value) => AssetSourceId::Name(value.into()), |             Some(value) => AssetSourceId::Name(CowArc::Borrowed(value)), | ||||||
|             None => AssetSourceId::Default, |             None => AssetSourceId::Default, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -302,7 +319,7 @@ pub struct AssetSourceBuilders { | |||||||
| impl AssetSourceBuilders { | impl AssetSourceBuilders { | ||||||
|     /// Inserts a new builder with the given `id`
 |     /// Inserts a new builder with the given `id`
 | ||||||
|     pub fn insert(&mut self, id: impl Into<AssetSourceId<'static>>, source: AssetSourceBuilder) { |     pub fn insert(&mut self, id: impl Into<AssetSourceId<'static>>, source: AssetSourceBuilder) { | ||||||
|         match id.into() { |         match AssetSourceId::from_static(id) { | ||||||
|             AssetSourceId::Default => { |             AssetSourceId::Default => { | ||||||
|                 self.default = Some(source); |                 self.default = Some(source); | ||||||
|             } |             } | ||||||
|  | |||||||
| @ -341,7 +341,7 @@ impl AssetApp for App { | |||||||
|         id: impl Into<AssetSourceId<'static>>, |         id: impl Into<AssetSourceId<'static>>, | ||||||
|         source: AssetSourceBuilder, |         source: AssetSourceBuilder, | ||||||
|     ) -> &mut Self { |     ) -> &mut Self { | ||||||
|         let id = id.into(); |         let id = AssetSourceId::from_static(id); | ||||||
|         if self.world().get_resource::<AssetServer>().is_some() { |         if self.world().get_resource::<AssetServer>().is_some() { | ||||||
|             error!("{} must be registered before `AssetPlugin` (typically added as part of `DefaultPlugins`)", id); |             error!("{} must be registered before `AssetPlugin` (typically added as part of `DefaultPlugins`)", id); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -475,14 +475,43 @@ impl<'a> AssetPath<'a> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl From<&'static str> for AssetPath<'static> { | impl AssetPath<'static> { | ||||||
|  |     /// Indicates this [`AssetPath`] should have a static lifetime.
 | ||||||
|     #[inline] |     #[inline] | ||||||
|     fn from(asset_path: &'static str) -> Self { |     pub fn as_static(self) -> Self { | ||||||
|  |         let Self { | ||||||
|  |             source, | ||||||
|  |             path, | ||||||
|  |             label, | ||||||
|  |         } = self; | ||||||
|  | 
 | ||||||
|  |         let source = source.as_static(); | ||||||
|  |         let path = path.as_static(); | ||||||
|  |         let label = label.map(CowArc::as_static); | ||||||
|  | 
 | ||||||
|  |         Self { | ||||||
|  |             source, | ||||||
|  |             path, | ||||||
|  |             label, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Constructs an [`AssetPath`] with a static lifetime.
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn from_static(value: impl Into<Self>) -> Self { | ||||||
|  |         value.into().as_static() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<'a> From<&'a str> for AssetPath<'a> { | ||||||
|  |     #[inline] | ||||||
|  |     fn from(asset_path: &'a str) -> Self { | ||||||
|         let (source, path, label) = Self::parse_internal(asset_path).unwrap(); |         let (source, path, label) = Self::parse_internal(asset_path).unwrap(); | ||||||
|  | 
 | ||||||
|         AssetPath { |         AssetPath { | ||||||
|             source: source.into(), |             source: source.into(), | ||||||
|             path: CowArc::Static(path), |             path: CowArc::Borrowed(path), | ||||||
|             label: label.map(CowArc::Static), |             label: label.map(CowArc::Borrowed), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -501,12 +530,12 @@ impl From<String> for AssetPath<'static> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl From<&'static Path> for AssetPath<'static> { | impl<'a> From<&'a Path> for AssetPath<'a> { | ||||||
|     #[inline] |     #[inline] | ||||||
|     fn from(path: &'static Path) -> Self { |     fn from(path: &'a Path) -> Self { | ||||||
|         Self { |         Self { | ||||||
|             source: AssetSourceId::Default, |             source: AssetSourceId::Default, | ||||||
|             path: CowArc::Static(path), |             path: CowArc::Borrowed(path), | ||||||
|             label: None, |             label: None, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -26,6 +26,18 @@ pub enum CowArc<'a, T: ?Sized + 'static> { | |||||||
|     Owned(Arc<T>), |     Owned(Arc<T>), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | impl<T: ?Sized> CowArc<'static, T> { | ||||||
|  |     /// Indicates this [`CowArc`] should have a static lifetime.
 | ||||||
|  |     /// This ensures if this was created with a value `Borrowed(&'static T)`, it is replaced with `Static(&'static T)`.
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn as_static(self) -> Self { | ||||||
|  |         match self { | ||||||
|  |             Self::Borrowed(value) | Self::Static(value) => Self::Static(value), | ||||||
|  |             Self::Owned(value) => Self::Owned(value), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| impl<'a, T: ?Sized> Deref for CowArc<'a, T> { | impl<'a, T: ?Sized> Deref for CowArc<'a, T> { | ||||||
|     type Target = T; |     type Target = T; | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Zachary Harrold
						Zachary Harrold