use std::{collections::HashMap, path::PathBuf};
use crossbeam_channel::Sender;
use distill_core::{ArtifactId, ArtifactMetadata, AssetMetadata, AssetUuid};
use crate::{loader::LoaderState, storage::IndirectIdentifier, LoadHandle, Result};
pub trait LoaderIO: Send + Sync {
fn get_asset_metadata_with_dependencies(&mut self, request: MetadataRequest);
fn get_asset_candidates(&mut self, requests: Vec<ResolveRequest>);
fn get_artifacts(&mut self, requests: Vec<DataRequest>);
fn tick(&mut self, loader: &mut LoaderState);
fn with_runtime(&self, f: &mut dyn FnMut(&tokio::runtime::Runtime));
}
pub struct DataRequest {
pub(crate) tx: Sender<(Result<Vec<u8>>, LoadHandle, u32)>,
pub(crate) asset_id: AssetUuid,
pub(crate) artifact_id: ArtifactId,
pub(crate) request_data: Option<(LoadHandle, u32)>,
}
impl DataRequest {
pub fn asset_id(&self) -> AssetUuid {
self.asset_id
}
pub fn artifact_id(&self) -> ArtifactId {
self.artifact_id
}
pub fn error<T: std::error::Error + Send + 'static>(mut self, err: T) {
if let Some(request_data) = self.request_data.take() {
let _ = self
.tx
.send((Err(Box::new(err)), request_data.0, request_data.1));
}
}
pub fn complete(mut self, data: Vec<u8>) {
if let Some(request_data) = self.request_data.take() {
let _ = self.tx.send((Ok(data), request_data.0, request_data.1));
}
}
}
impl Drop for DataRequest {
fn drop(&mut self) {
if let Some(request_data) = self.request_data.take() {
let _ = self.tx.send((
Err(Box::new(RequestDropError)),
request_data.0,
request_data.1,
));
}
}
}
#[allow(clippy::type_complexity)]
pub struct ResolveRequest {
pub(crate) tx: Sender<(
Result<Vec<(PathBuf, Vec<AssetMetadata>)>>,
IndirectIdentifier,
LoadHandle,
)>,
pub(crate) id: Option<(IndirectIdentifier, LoadHandle)>,
}
impl ResolveRequest {
pub fn identifier(&self) -> &IndirectIdentifier {
self.id.as_ref().map(|v| &v.0).unwrap()
}
pub fn error<T: std::error::Error + Send + 'static>(mut self, err: T) {
if let Some(id) = self.id.take() {
let _ = self.tx.send((Err(Box::new(err)), id.0, id.1));
}
}
pub fn complete(mut self, data: Vec<(PathBuf, Vec<AssetMetadata>)>) {
if let Some(id) = self.id.take() {
let _ = self.tx.send((Ok(data), id.0, id.1));
}
}
}
impl Drop for ResolveRequest {
fn drop(&mut self) {
if let Some(id) = self.id.take() {
let _ = self.tx.send((Err(Box::new(RequestDropError)), id.0, id.1));
}
}
}
#[derive(Debug)]
struct RequestDropError;
impl std::fmt::Display for RequestDropError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("request dropped")
}
}
impl std::error::Error for RequestDropError {}
pub struct MetadataRequestResult {
pub artifact_metadata: ArtifactMetadata,
pub asset_metadata: Option<AssetMetadata>,
}
#[allow(clippy::type_complexity)]
pub struct MetadataRequest {
pub(crate) tx: Sender<(
Result<Vec<MetadataRequestResult>>,
HashMap<AssetUuid, (LoadHandle, u32)>,
)>,
pub(crate) requests: Option<HashMap<AssetUuid, (LoadHandle, u32)>>,
pub(crate) include_asset_metadata: bool,
}
impl MetadataRequest {
pub fn requested_assets(&self) -> impl Iterator<Item = &AssetUuid> {
self.requests.as_ref().unwrap().keys()
}
pub fn include_asset_metadata(&self) -> bool {
self.include_asset_metadata
}
pub fn error<T: std::error::Error + Send + 'static>(mut self, err: T) {
if let Some(requests) = self.requests.take() {
let _ = self.tx.send((Err(Box::new(err)), requests));
}
}
pub fn complete(mut self, metadata: Vec<MetadataRequestResult>) {
if let Some(requests) = self.requests.take() {
let _ = self.tx.send((Ok(metadata), requests));
}
}
}
impl Drop for MetadataRequest {
fn drop(&mut self) {
if let Some(requests) = self.requests.take() {
let _ = self.tx.send((Err(Box::new(RequestDropError)), requests));
}
}
}