use std::{collections::HashMap, pin::Pin};
use bevy::prelude::*;
use super::{BundleEntry, LoadAssetFrom};
use crate::prelude::*;
#[macro_export]
macro_rules! call_load_from {
($A: ty, $key: expr, $entry: expr, $load_context: expr) => {{
#[allow(unused_imports)]
use $crate::assets::bundle::{
CallLoadAssetFrom as _, CallLoadFromWrapper, LoadAssetFrom as _,
};
(&&&&CallLoadFromWrapper::<$A>::new()).call_load_from($key, $entry, $load_context)
}};
}
pub use call_load_from;
#[macro_export]
macro_rules! load_handle_from {
($H: ty, $key: expr, $entry: expr, $load_context: expr) => {{
#[allow(unused_imports)]
use $crate::assets::bundle::{
AssetHandleWrapper, CallLoadAssetFrom as _, LoadAssetFrom as _,
};
(&&&AssetHandleWrapper::<$H>::new()).load_handle_from($key, $entry, $load_context)
}};
}
pub use load_handle_from;
pub struct CallLoadFromWrapper<A: ?Sized> {
phantom_data: std::marker::PhantomData<A>,
}
impl<A: ?Sized> Default for CallLoadFromWrapper<A> {
fn default() -> Self {
Self::new()
}
}
impl<A: ?Sized> CallLoadFromWrapper<A> {
pub fn new() -> Self {
Self {
phantom_data: Default::default(),
}
}
}
pub struct AssetHandleWrapper<H: ?Sized> {
phantom_data: std::marker::PhantomData<H>,
}
impl<A: Asset> Default for AssetHandleWrapper<Handle<A>> {
fn default() -> Self {
Self::new()
}
}
impl<A: Asset> AssetHandleWrapper<Handle<A>> {
pub fn new() -> Self {
Self {
phantom_data: Default::default(),
}
}
}
pub trait CallLoadAssetFrom {
type Target;
fn call_load_from<'a, 's>(
&'s self,
key: String,
entry: BundleEntry,
load_context: &'a mut bevy::asset::LoadContext<'_>,
) -> Pin<Box<dyn Future<Output = Result<Self::Target, Error>> + Send + 'a>>;
}
impl<A: Asset + LoadAssetFrom> CallLoadAssetFrom for &CallLoadFromWrapper<A> {
type Target = A;
fn call_load_from<'a, 's>(
&'s self,
key: String,
entry: BundleEntry,
load_context: &'a mut bevy::asset::LoadContext<'_>,
) -> Pin<Box<dyn Future<Output = Result<Self::Target, Error>> + Send + 'a>> {
A::load_from(key, entry, load_context)
}
}
impl<A: Asset + Sized> CallLoadAssetFrom for CallLoadFromWrapper<A> {
type Target = A;
fn call_load_from<'a, 's>(
&'s self,
key: String,
entry: BundleEntry,
load_context: &'a mut bevy::asset::LoadContext<'_>,
) -> Pin<Box<dyn Future<Output = Result<Self::Target, Error>> + Send + 'a>> {
Box::pin(async {
match entry {
BundleEntry::File(path) => {
let path = load_context.asset_path().parent().unwrap().resolve(&path)?;
Ok(load_context.loader().immediate().load(path).await?.take())
}
_ => Err(Error::IncompatibleEntry { key }),
}
})
}
}
impl<A: Asset + LoadAssetFrom> CallLoadAssetFrom for &&CallLoadFromWrapper<Handle<A>> {
type Target = Handle<A>;
fn call_load_from<'a, 's>(
&'s self,
key: String,
entry: BundleEntry,
load_context: &'a mut bevy::asset::LoadContext<'_>,
) -> Pin<Box<dyn Future<Output = Result<Self::Target, Error>> + Send + 'a>> {
Box::pin(async {
let a = A::load_from(key, entry, load_context).await?;
Ok(load_context.add_labeled_asset(String::new(), a))
})
}
}
impl<A: Asset + Sized> CallLoadAssetFrom for &CallLoadFromWrapper<Handle<A>> {
type Target = Handle<A>;
fn call_load_from<'a, 's>(
&'s self,
key: String,
entry: BundleEntry,
load_context: &'a mut bevy::asset::LoadContext<'_>,
) -> Pin<Box<dyn Future<Output = Result<Self::Target, Error>> + Send + 'a>> {
Box::pin(async {
match entry {
BundleEntry::File(path) => {
let path = load_context.asset_path().parent().unwrap().resolve(&path)?;
Ok(load_context.load(path))
}
_ => Err(Error::IncompatibleEntry { key }),
}
})
}
}
impl<A: Asset + std::fmt::Debug + LoadAssetFrom> CallLoadAssetFrom
for &&&CallLoadFromWrapper<HashMap<String, Handle<A>>>
{
type Target = HashMap<String, Handle<A>>;
fn call_load_from<'a, 's>(
&'s self,
key: String,
entry: BundleEntry,
load_context: &'a mut bevy::asset::LoadContext<'_>,
) -> Pin<Box<dyn Future<Output = Result<Self::Target, Error>> + Send + 'a>> {
Box::pin(async {
match entry {
BundleEntry::Bundle(assets) => {
let mut m = HashMap::<String, Handle<A>>::default();
for (k, v) in assets {
let a = call_load_from!(A, k.to_owned(), v, load_context).await?;
let h = load_context.add_labeled_asset(k.clone(), a);
m.insert(k.clone(), h);
}
Ok(m)
}
_ => Err(Error::IncompatibleEntry { key }),
}
})
}
}
impl<A: Asset + std::fmt::Debug> CallLoadAssetFrom
for &&CallLoadFromWrapper<HashMap<String, Handle<A>>>
{
type Target = HashMap<String, Handle<A>>;
fn call_load_from<'a, 's>(
&'s self,
key: String,
entry: BundleEntry,
load_context: &'a mut bevy::asset::LoadContext<'_>,
) -> Pin<Box<dyn Future<Output = Result<Self::Target, Error>> + Send + 'a>> {
Box::pin(async {
match entry {
BundleEntry::Bundle(assets) => {
let mut m = HashMap::<String, Handle<A>>::default();
for (k, v) in assets {
let a = call_load_from!(A, k.to_owned(), v, load_context).await?;
let h = load_context.add_labeled_asset(k.clone(), a);
m.insert(k.clone(), h);
}
Ok(m)
}
_ => Err(Error::IncompatibleEntry { key }),
}
})
}
}
impl<A: Asset + LoadAssetFrom> CallLoadAssetFrom for &&CallLoadFromWrapper<HashMap<String, A>> {
type Target = HashMap<String, A>;
fn call_load_from<'a, 's>(
&'s self,
key: String,
entry: BundleEntry,
load_context: &'a mut bevy::asset::LoadContext<'_>,
) -> Pin<Box<dyn Future<Output = Result<Self::Target, Error>> + Send + 'a>> {
Box::pin(async {
match entry {
BundleEntry::Bundle(assets) => {
let mut m = HashMap::<String, A>::default();
for (k, v) in assets {
m.insert(k.to_owned(), call_load_from!(A, k, v, load_context).await?);
}
Ok(m)
}
_ => Err(Error::IncompatibleEntry { key }),
}
})
}
}
impl CallLoadAssetFrom for &&CallLoadFromWrapper<Vec<String>> {
type Target = Vec<String>;
fn call_load_from<'a, 's>(
&'s self,
key: String,
entry: BundleEntry,
_load_context: &'a mut bevy::asset::LoadContext<'_>,
) -> Pin<Box<dyn Future<Output = Result<Self::Target, Error>> + Send + 'a>> {
Box::pin(async {
match entry {
BundleEntry::List(assets) => {
let mut m = Vec::<String>::default();
for v in assets {
match v {
BundleEntry::Text(content) => m.push(content),
_ => return Err(Error::IncompatibleEntry { key }),
}
}
Ok(m)
}
BundleEntry::StringList(list) => Ok(list),
_ => Err(Error::IncompatibleEntry { key }),
}
})
}
}
impl CallLoadAssetFrom for &&CallLoadFromWrapper<f32> {
type Target = f32;
fn call_load_from<'a, 's>(
&'s self,
key: String,
entry: BundleEntry,
_load_context: &'a mut bevy::asset::LoadContext<'_>,
) -> Pin<Box<dyn Future<Output = Result<Self::Target, Error>> + Send + 'a>> {
Box::pin(async move {
match entry {
BundleEntry::Float(f) => Ok(f as f32),
_ => Err(Error::IncompatibleEntry { key }),
}
})
}
}
impl CallLoadAssetFrom for &&CallLoadFromWrapper<Color> {
type Target = Color;
fn call_load_from<'a, 's>(
&'s self,
key: String,
entry: BundleEntry,
_load_context: &'a mut bevy::asset::LoadContext<'_>,
) -> Pin<Box<dyn Future<Output = Result<Self::Target, Error>> + Send + 'a>> {
Box::pin(async move {
match entry {
BundleEntry::Color(c) => Ok(c),
_ => Err(Error::IncompatibleEntry { key }),
}
})
}
}
impl CallLoadAssetFrom for &&CallLoadFromWrapper<UiRect> {
type Target = UiRect;
fn call_load_from<'a, 's>(
&'s self,
key: String,
entry: BundleEntry,
_load_context: &'a mut bevy::asset::LoadContext<'_>,
) -> Pin<Box<dyn Future<Output = Result<Self::Target, Error>> + Send + 'a>> {
Box::pin(async move {
match entry {
BundleEntry::UiRect(c) => Ok(c),
_ => Err(Error::IncompatibleEntry { key }),
}
})
}
}
impl CallLoadAssetFrom for &&CallLoadFromWrapper<TextureSlicer> {
type Target = TextureSlicer;
fn call_load_from<'a, 's>(
&'s self,
key: String,
entry: BundleEntry,
_load_context: &'a mut bevy::asset::LoadContext<'_>,
) -> Pin<Box<dyn Future<Output = Result<Self::Target, Error>> + Send + 'a>> {
Box::pin(async move {
match entry {
BundleEntry::TextureSlicer(c) => Ok(c),
_ => Err(Error::IncompatibleEntry { key }),
}
})
}
}