use std::borrow::Borrow;
use std::fmt::Debug;
use std::hash::Hash;
use std::ops::Deref;
use std::path::PathBuf;
use bevy::asset::{Asset, AssetPath, LoadContext};
use bevy::prelude::*;
use bincode::{Encode, Decode, BorrowDecode};
use bincode::de::{BorrowDecoder, Decoder};
use bincode::enc::Encoder;
use bincode::error::{DecodeError, EncodeError};
use derivative::Derivative;
use once_cell::sync::OnceCell;
use serde::{Serialize, Deserialize, Deserializer};
#[derive(Clone)]
#[derive(Serialize, Deserialize)]
#[serde(bound(serialize = "K: Serialize"))]
#[serde(bound(deserialize = "K: Deserialize<'de>"))]
#[serde(transparent)]
#[derive(Derivative)]
#[derivative(Default(bound = "K: Default"))]
#[derivative(Hash(bound = "K: Hash"))]
#[derivative(Debug(bound = "K: Debug"), Debug = "transparent")]
#[derivative(Eq(bound = "K: Eq"), PartialEq(bound = "K: PartialEq"))]
pub struct Cached<K, I> {
pub raw_key: K,
#[derivative(Debug = "ignore")]
#[derivative(Hash = "ignore")]
#[derivative(PartialEq = "ignore")]
#[serde(skip)]
pub cached: OnceCell<I>,
}
impl<K, I> Cached<K, I> {
pub const fn new(raw_key: K) -> Self { Cached { raw_key, cached: OnceCell::new() } }
pub fn get_handle_or_lazy_init<'a, C>(&self, container: impl FnOnce() -> &'a C) -> Option<I>
where C: ContainerWithKey<Handle = I> + 'a, K: Borrow<C::Key>, I: Clone {
Some(self.cached.get_or_try_init(|| {
container().get_by_key(self.raw_key.borrow()).ok_or(())
}).ok()?.clone())
}
pub fn get_handle_or_init<C>(&self, container: &C) -> Option<I>
where C: ContainerWithKey<Handle = I>, K: Borrow<C::Key>, I: Clone {
self.get_handle_or_lazy_init(|| container)
}
pub fn get_or_init<'a, C>(&self, container: &'a C) -> Option<&'a C::Value>
where C: ContainerWithKey<Handle = I>, K: Borrow<C::Key>, I: Clone {
Some(container.get_by_handle(self.get_handle_or_init(container)?))
}
}
impl<T: Asset> Cached<PathBuf, Handle<T>> {
pub fn asset_path(&self) -> AssetPath { AssetPath::from_path(&self.raw_key) }
pub fn init_handle(&self, load_context: &mut LoadContext) {
let handle = load_context.load(self.asset_path());
self.cached.set(handle).unwrap();
}
pub fn get<'a>(&self, assets: &'a Assets<T>) -> Option<&'a T> {
assets.get(self.cached.get()?)
}
pub fn get_mut<'a>(&self, assets: &'a mut Assets<T>) -> Option<&'a mut T> {
assets.get_mut(self.cached.get()?)
}
}
impl<K, I> From<K> for Cached<K, I> {
fn from(raw_key: K) -> Self { Cached { raw_key, cached: OnceCell::new() } }
}
impl<K: Encode, I> Encode for Cached<K, I> {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.raw_key.encode(encoder)
}
}
impl<K: Decode, I> Decode for Cached<K, I> {
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
Ok(Cached::from(K::decode(decoder)?))
}
}
impl<'de, K: BorrowDecode<'de>, I> BorrowDecode<'de> for Cached<K, I> {
fn borrow_decode<D: BorrowDecoder<'de>>(decoder: &mut D) -> Result<Self, DecodeError> {
Ok(Cached::from(K::borrow_decode(decoder)?))
}
}
pub trait EntryWithKey {
type Key: ?Sized;
fn key(&self) -> &Self::Key;
}
pub trait ContainerWithKey {
type Handle;
type Key: ?Sized;
type Value: ?Sized;
fn get_by_handle(&self, handle: Self::Handle) -> &Self::Value;
fn get_by_key(&self, key: &Self::Key) -> Option<Self::Handle>;
}
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
#[derive(Serialize, Encode)]
#[serde(transparent)]
pub struct SortedSlice<T>(Box<[T]>);
impl<T> Default for SortedSlice<T> {
fn default() -> Self { SortedSlice(Box::default()) }
}
impl<T> Deref for SortedSlice<T> {
type Target = [T];
fn deref(&self) -> &[T] { self.0.as_ref() }
}
impl<T> AsRef<[T]> for SortedSlice<T> {
fn as_ref(&self) -> &[T] { self.deref() }
}
impl<T> Borrow<[T]> for SortedSlice<T> {
fn borrow(&self) -> &[T] { self.deref() }
}
impl<T: EntryWithKey> From<Vec<T>> for SortedSlice<T>
where T::Key: Ord {
fn from(xs: Vec<T>) -> Self { xs.into_boxed_slice().into() }
}
impl<T: EntryWithKey> From<Box<[T]>> for SortedSlice<T>
where T::Key: Ord {
fn from(mut xs: Box<[T]>) -> Self {
xs.sort_unstable_by(|x, y| Ord::cmp(x.key(), y.key()));
SortedSlice(xs)
}
}
impl<E: EntryWithKey> ContainerWithKey for SortedSlice<E>
where E::Key: Ord {
type Handle = usize;
type Key = E::Key;
type Value = E;
fn get_by_handle(&self, handle: usize) -> &E { &self[handle] }
fn get_by_key(&self, key: &E::Key) -> Option<usize> {
self.binary_search_by(|x| x.key().cmp(key)).ok()
}
}
impl<'de, T> Deserialize<'de> for SortedSlice<T>
where T: EntryWithKey + Deserialize<'de>, T::Key: Ord {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
Box::<[T]>::deserialize(deserializer).map(SortedSlice::from)
}
}
impl<T> Decode for SortedSlice<T>
where T: EntryWithKey + Decode, T::Key: Ord {
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
Box::<[T]>::decode(decoder).map(SortedSlice::from)
}
}
impl<'de, T> BorrowDecode<'de> for SortedSlice<T>
where T: EntryWithKey + BorrowDecode<'de> + 'de, T::Key: Ord {
fn borrow_decode<D: BorrowDecoder<'de>>(decoder: &mut D) -> Result<Self, DecodeError> {
Box::<[T]>::borrow_decode(decoder).map(SortedSlice::from)
}
}