distill_loader/
io.rs

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
8/// Provides [`Loader`](crate::loader::Loader) with data.
9pub 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
17/// A request for an asset artifact's data.
18pub 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/// A request for possible candidates for an [`IndirectIdentifier`].
60#[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/// A request for artifact metadata covering the dependency graphs of the requested asset IDs.
107#[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    /// Whether the response should include asset metadata or not, for debugging purposes.
122    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}