1use std::{collections::HashMap, path::PathBuf};
2
3use crossbeam_channel::Sender;
4use distill_core::{ArtifactId, ArtifactMetadata, AssetMetadata, AssetUuid};
5
6use crate::{loader::LoaderState, storage::IndirectIdentifier, LoadHandle, Result};
7
8pub trait LoaderIO: Send + Sync {
10 fn get_asset_metadata_with_dependencies(&mut self, request: MetadataRequest);
11 fn get_asset_candidates(&mut self, requests: Vec<ResolveRequest>);
12 fn get_artifacts(&mut self, requests: Vec<DataRequest>);
13 fn tick(&mut self, loader: &mut LoaderState);
14 fn with_runtime(&self, f: &mut dyn FnMut(&tokio::runtime::Runtime));
15}
16
17pub struct DataRequest {
19 pub(crate) tx: Sender<(Result<Vec<u8>>, LoadHandle, u32)>,
20 pub(crate) asset_id: AssetUuid,
21 pub(crate) artifact_id: ArtifactId,
22 pub(crate) request_data: Option<(LoadHandle, u32)>,
23}
24impl DataRequest {
25 pub fn asset_id(&self) -> AssetUuid {
26 self.asset_id
27 }
28
29 pub fn artifact_id(&self) -> ArtifactId {
30 self.artifact_id
31 }
32
33 pub fn error<T: std::error::Error + Send + 'static>(mut self, err: T) {
34 if let Some(request_data) = self.request_data.take() {
35 let _ = self
36 .tx
37 .send((Err(Box::new(err)), request_data.0, request_data.1));
38 }
39 }
40
41 pub fn complete(mut self, data: Vec<u8>) {
42 if let Some(request_data) = self.request_data.take() {
43 let _ = self.tx.send((Ok(data), request_data.0, request_data.1));
44 }
45 }
46}
47impl Drop for DataRequest {
48 fn drop(&mut self) {
49 if let Some(request_data) = self.request_data.take() {
50 let _ = self.tx.send((
51 Err(Box::new(RequestDropError)),
52 request_data.0,
53 request_data.1,
54 ));
55 }
56 }
57}
58
59#[allow(clippy::type_complexity)]
61pub struct ResolveRequest {
62 pub(crate) tx: Sender<(
63 Result<Vec<(PathBuf, Vec<AssetMetadata>)>>,
64 IndirectIdentifier,
65 LoadHandle,
66 )>,
67 pub(crate) id: Option<(IndirectIdentifier, LoadHandle)>,
68}
69impl ResolveRequest {
70 pub fn identifier(&self) -> &IndirectIdentifier {
71 self.id.as_ref().map(|v| &v.0).unwrap()
72 }
73
74 pub fn error<T: std::error::Error + Send + 'static>(mut self, err: T) {
75 if let Some(id) = self.id.take() {
76 let _ = self.tx.send((Err(Box::new(err)), id.0, id.1));
77 }
78 }
79
80 pub fn complete(mut self, data: Vec<(PathBuf, Vec<AssetMetadata>)>) {
81 if let Some(id) = self.id.take() {
82 let _ = self.tx.send((Ok(data), id.0, id.1));
83 }
84 }
85}
86impl Drop for ResolveRequest {
87 fn drop(&mut self) {
88 if let Some(id) = self.id.take() {
89 let _ = self.tx.send((Err(Box::new(RequestDropError)), id.0, id.1));
90 }
91 }
92}
93#[derive(Debug)]
94struct RequestDropError;
95impl std::fmt::Display for RequestDropError {
96 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97 f.write_str("request dropped")
98 }
99}
100impl std::error::Error for RequestDropError {}
101
102pub struct MetadataRequestResult {
103 pub artifact_metadata: ArtifactMetadata,
104 pub asset_metadata: Option<AssetMetadata>,
105}
106#[allow(clippy::type_complexity)]
108pub struct MetadataRequest {
109 pub(crate) tx: Sender<(
110 Result<Vec<MetadataRequestResult>>,
111 HashMap<AssetUuid, (LoadHandle, u32)>,
112 )>,
113 pub(crate) requests: Option<HashMap<AssetUuid, (LoadHandle, u32)>>,
114 pub(crate) include_asset_metadata: bool,
115}
116impl MetadataRequest {
117 pub fn requested_assets(&self) -> impl Iterator<Item = &AssetUuid> {
118 self.requests.as_ref().unwrap().keys()
119 }
120
121 pub fn include_asset_metadata(&self) -> bool {
123 self.include_asset_metadata
124 }
125
126 pub fn error<T: std::error::Error + Send + 'static>(mut self, err: T) {
127 if let Some(requests) = self.requests.take() {
128 let _ = self.tx.send((Err(Box::new(err)), requests));
129 }
130 }
131
132 pub fn complete(mut self, metadata: Vec<MetadataRequestResult>) {
133 if let Some(requests) = self.requests.take() {
134 let _ = self.tx.send((Ok(metadata), requests));
135 }
136 }
137}
138
139impl Drop for MetadataRequest {
140 fn drop(&mut self) {
141 if let Some(requests) = self.requests.take() {
142 let _ = self.tx.send((Err(Box::new(RequestDropError)), requests));
143 }
144 }
145}