1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
use std::borrow::Borrow;
use bevy::asset::AssetPath;
/// A type that can be used as key for mapped asset collection.
///
/// # `String` and `Box<str>`
///
/// Both [`String`] and [`Box<str>`] implements [`MapKey`] by using
/// the path of the asset as the key.
///
/// # Key collision
///
/// Following the implementation of the [`MapKey`] trait, key collisions may happen,
/// resulting in some assets not being loaded.
/// This is up to the user to ensure that there are no collisions.
pub trait MapKey {
/// Creates the key from the path of the asset.
fn from_asset_path(path: &AssetPath) -> Self;
}
/// Implements extra traits and methods for the key types.
macro_rules! impl_map_key_extras {
($Key:ty) => {
impl AsRef<str> for $Key {
#[inline]
fn as_ref(&self) -> &str {
&self.0
}
}
// Note: required by `HashMap::get` to being able to use &str.
impl Borrow<str> for $Key {
#[inline]
fn borrow(&self) -> &str {
&self.0
}
}
impl From<$Key> for Box<str> {
#[inline]
fn from(key: $Key) -> Self {
key.0
}
}
impl From<$Key> for String {
#[inline]
fn from(key: $Key) -> Self {
key.0.into()
}
}
};
}
/// A [`MapKey`] that uses the [`file_name`] of the asset's path as key.
///
/// # Key collision
///
/// Since [`AssetFileName`] uses a subset of the asset path, two different assets may have the same key.
/// It’s up to you to ensure there is no collision.
///
/// Here's an example that will result in a key clash.
///
/// ```plain
/// folder
/// subfolder_a
/// file.png
/// subfolder_b
/// file.png
/// ```
///
/// [`file_name`]: std::path::Path::file_name
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AssetFileName(Box<str>);
impl_map_key_extras!(AssetFileName);
impl MapKey for AssetFileName {
#[inline]
fn from_asset_path(path: &AssetPath) -> Self {
Self(
path.path()
.file_name()
.unwrap()
.to_str()
.expect("Path should be valid UTF-8")
.into(),
)
}
}
/// A [`MapKey`] that uses the [`file_stem`] of the asset's path as key.
///
/// # Key collision
///
/// Since [`AssetFileStem`] uses a subset of the asset path, two different assets may have the same key.
/// It’s up to you to ensure there is no collision.
///
/// Here's an example that will result in a key clash.
///
/// ```plain
/// folder
/// file.png
/// file.jpg
/// ```
///
/// [`file_stem`]: std::path::Path::file_stem
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AssetFileStem(Box<str>);
impl_map_key_extras!(AssetFileStem);
impl MapKey for AssetFileStem {
#[inline]
fn from_asset_path(path: &AssetPath) -> Self {
Self(
path.path()
.file_stem()
.unwrap()
.to_str()
.expect("Path should be valid UTF-8")
.into(),
)
}
}
/// A [`MapKey`] that uses the [`label`] of the asset's path as key.
///
/// # Panics
///
/// This type requires every asset in the collection to be loaded with a label.
/// If an asset path does not have a label, it will panic.
///
/// [`label`]: AssetPath::label
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AssetLabel(Box<str>);
impl_map_key_extras!(AssetLabel);
impl MapKey for AssetLabel {
#[inline]
fn from_asset_path(path: &AssetPath) -> Self {
Self(path.label().expect("Asset does not have a label").into())
}
}
impl MapKey for String {
#[inline]
fn from_asset_path(path: &AssetPath) -> Self {
path_slash::PathExt::to_slash(path.path())
.expect("Path should be valid UTF-8")
.into()
}
}
impl MapKey for Box<str> {
#[inline]
fn from_asset_path(path: &AssetPath) -> Self {
path_slash::PathExt::to_slash(path.path())
.expect("Path should be valid UTF-8")
.into()
}
}