import { warn } from '../../utils/logging/warn';
import { convertToList } from '../utils/convertToList';
import type { CacheParser } from './CacheParser';
/**
* A single Cache for all assets.
*
* When assets are added to the cache via set they normally are added to the cache as key-value pairs.
*
* With this cache, you can add parsers that will take the object and convert it to a list of assets that can be cached.
* for example a cacheSpritesheet parser will add all of the textures found within its sprite sheet directly to the cache.
*
* This gives devs the flexibility to cache any type of object however we want.
*
* It is not intended that this class is created by developers - it is part of the Asset package.
* This is the first major system of PixiJS' main Assets class.
* @example
* import { Cache } from 'pixi.js';
*
* Cache.set('bunny', bunnyTexture);
* @class Cache
* @memberof assets
*/
class CacheClass
{
private readonly _parsers: CacheParser[] = [];
private readonly _cache: Map<any, any> = new Map();
private readonly _cacheMap: Map<string, {
keys: string[],
cacheKeys: string[],
}> = new Map();
/** Clear all entries. */
public reset(): void
{
this._cacheMap.clear();
this._cache.clear();
}
/**
* Check if the key exists
* @param key - The key to check
*/
public has(key: any): boolean
{
return this._cache.has(key);
}
/**
* Fetch entry by key
* @param key - The key of the entry to get
*/
public get<T = any>(key: any): T
{
const result = this._cache.get(key);
if (!result)
{
// #if _DEBUG
warn(`[Assets] Asset id ${key} was not found in the Cache`);
// #endif
}
return result as T;
}
/**
* Set a value by key or keys name
* @param key - The key or keys to set
* @param value - The value to store in the cache or from which cacheable assets will be derived.
*/
public set(key: any | any[], value: unknown): void
{
const keys = convertToList<string>(key);
let cacheableAssets: Record<string, any>;
for (let i = 0; i < this.parsers.length; i++)
{
const parser = this.parsers[i];
if (parser.test(value))
{
cacheableAssets = parser.getCacheableAssets(keys, value);
break;
}
}
// convert cacheable assets to a map of key-value pairs
const cacheableMap = new Map(Object.entries(cacheableAssets || {}));
if (!cacheableAssets)
{
keys.forEach((key) =>
{
cacheableMap.set(key, value);
});
}
const cacheKeys = [...cacheableMap.keys()];
const cachedAssets = {
cacheKeys,
keys
};
// this is so we can remove them later..
keys.forEach((key) =>
{
this._cacheMap.set(key, cachedAssets as any);
});
cacheKeys.forEach((key) =>
{
const val = cacheableAssets ? cacheableAssets[key] : value;
if (this._cache.has(key) && this._cache.get(key) !== val)
{
// #if _DEBUG
warn('[Cache] already has key:', key);
// #endif
}
this._cache.set(key, cacheableMap.get(key));
});
}
/**
* Remove entry by key
*
* This function will also remove any associated alias from the cache also.
* @param key - The key of the entry to remove
*/
public remove(key: any): void
{
if (!this._cacheMap.has(key))
{
// #if _DEBUG
warn(`[Assets] Asset id ${key} was not found in the Cache`);
// #endif
return;
}
const cacheMap = this._cacheMap.get(key);
const cacheKeys = cacheMap.cacheKeys;
cacheKeys.forEach((key) =>
{
this._cache.delete(key);
});
cacheMap.keys.forEach((key: string) =>
{
this._cacheMap.delete(key);
});
}
/** All loader parsers registered */
public get parsers(): CacheParser[]
{
return this._parsers;
}
}
export const Cache = new CacheClass();