distill_importer/
lib.rs

1mod boxed_importer;
2mod error;
3mod serde_obj;
4mod serialized_asset;
5
6#[cfg(feature = "serde_importers")]
7mod ron_importer;
8use std::io::{Read, Write};
9
10pub use distill_core::{
11    importer_context::{ImporterContext, ImporterContextHandle},
12    ArtifactMetadata, AssetMetadata,
13};
14use distill_core::{AssetRef, AssetUuid};
15use futures::{future::BoxFuture, AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
16pub use serde;
17use serde::Serialize;
18#[cfg(feature = "serde_importers")]
19pub use distill_serde_importable_derive::*;
20
21pub use self::error::{Error, Result};
22#[cfg(feature = "serde_importers")]
23pub use crate::ron_importer::{RonImporter, RonImporterOptions, RonImporterState};
24#[doc(hidden)]
25#[cfg(feature = "serde_importers")]
26pub use crate::serde_obj::typetag;
27#[cfg(feature = "serde_importers")]
28pub use crate::serde_obj::SerdeImportable;
29pub use crate::{
30    boxed_importer::{BoxedImporter, SourceMetadata, SOURCEMETADATA_VERSION},
31    serde_obj::{IntoSerdeObj, SerdeObj},
32    serialized_asset::SerializedAsset,
33};
34
35#[derive(Default)]
36pub struct ImportOp {
37    pub errors: Vec<Box<dyn std::error::Error + Send + 'static>>,
38    pub warnings: Vec<Box<dyn std::error::Error + Send + 'static>>,
39}
40
41impl ImportOp {
42    pub fn error<T: Into<Box<dyn std::error::Error + Send + 'static>>>(&mut self, err: T) {
43        self.errors.push(err.into());
44    }
45
46    pub fn warn<T: Into<Box<dyn std::error::Error + Send + 'static>>>(&mut self, err: T) {
47        self.warnings.push(err.into());
48    }
49
50    pub fn new_asset_uuid(&self) -> AssetUuid {
51        AssetUuid(*uuid::Uuid::new_v4().as_bytes())
52    }
53}
54
55/// Importers parse file formats and produce assets.
56pub trait Importer: Send + 'static {
57    /// Returns the version of the importer.
58    /// This version should change any time the importer behaviour changes to
59    /// trigger reimport of assets.
60    fn version_static() -> u32
61    where
62        Self: Sized;
63    /// Returns the version of the importer.
64    /// This version should change any time the importer behaviour changes to
65    /// trigger reimport of assets.
66    fn version(&self) -> u32;
67
68    /// Options can store settings that change importer behaviour.
69    /// Will be automatically stored in .meta files and passed to [Importer::import].
70    type Options: Send + Sync + 'static;
71
72    /// State is maintained by the asset pipeline to enable Importers to
73    /// store state between calls to import().
74    /// This is primarily used to ensure IDs are stable between imports
75    /// by storing generated AssetUuids with mappings to format-internal identifiers.
76    type State: Serialize + Send + 'static;
77
78    /// Reads the given bytes and produces assets.
79    fn import(
80        &self,
81        op: &mut ImportOp,
82        source: &mut dyn Read,
83        options: &Self::Options,
84        state: &mut Self::State,
85    ) -> Result<ImporterValue>;
86
87    /// Writes a set of assets to a source file format that can be read by `import`.
88    fn export(
89        &self,
90        _output: &mut dyn Write,
91        _options: &Self::Options,
92        _state: &mut Self::State,
93        _assets: Vec<ExportAsset>,
94    ) -> Result<ImporterValue> {
95        Err(Error::ExportUnsupported)
96    }
97}
98
99/// Importers parse file formats and produce assets.
100pub trait AsyncImporter: Send + 'static {
101    /// Returns the version of the importer.
102    /// This version should change any time the importer behaviour changes to
103    /// trigger reimport of assets.
104    fn version_static() -> u32
105    where
106        Self: Sized;
107    /// Returns the version of the importer.
108    /// This version should change any time the importer behaviour changes to
109    /// trigger reimport of assets.
110    fn version(&self) -> u32;
111
112    /// Options can store settings that change importer behaviour.
113    /// Will be automatically stored in .meta files and passed to [Importer::import].
114    type Options: Send + Sync + 'static;
115
116    /// State is maintained by the asset pipeline to enable Importers to
117    /// store state between calls to import().
118    /// This is primarily used to ensure IDs are stable between imports
119    /// by storing generated AssetUuids with mappings to format-internal identifiers.
120    type State: Serialize + Send + 'static;
121
122    /// Reads the given bytes and produces assets.
123    fn import<'a>(
124        &'a self,
125        op: &'a mut ImportOp,
126        source: &'a mut (dyn AsyncRead + Unpin + Send + Sync),
127        options: &'a Self::Options,
128        state: &'a mut Self::State,
129    ) -> BoxFuture<'a, Result<ImporterValue>>;
130
131    /// Writes a set of assets to a source file format that can be read by `import`.
132    fn export<'a>(
133        &'a self,
134        _output: &'a mut (dyn AsyncWrite + Unpin + Send + Sync),
135        _options: &'a Self::Options,
136        _state: &'a mut Self::State,
137        _assets: Vec<ExportAsset>,
138    ) -> BoxFuture<'a, Result<ImporterValue>> {
139        Box::pin(async move { Err(Error::ExportUnsupported) })
140    }
141}
142
143impl<T: Importer + Sync> AsyncImporter for T {
144    /// Options can store settings that change importer behaviour.
145    /// Will be automatically stored in .meta files and passed to [Importer::import].
146    type Options = <T as Importer>::Options;
147    /// State is maintained by the asset pipeline to enable Importers to
148    /// store state between calls to import().
149    /// This is primarily used to ensure IDs are stable between imports
150    /// by storing generated AssetUuids with mappings to format-internal identifiers.
151    type State = <T as Importer>::State;
152
153    fn version_static() -> u32
154    where
155        Self: Sized,
156    {
157        <T as Importer>::version_static()
158    }
159
160    fn version(&self) -> u32 {
161        <T as Importer>::version(self)
162    }
163
164    /// Reads the given bytes and produces assets.
165    fn import<'a>(
166        &'a self,
167        op: &'a mut ImportOp,
168        source: &'a mut (dyn AsyncRead + Unpin + Send + Sync),
169        options: &'a Self::Options,
170        state: &'a mut Self::State,
171    ) -> BoxFuture<'a, Result<ImporterValue>> {
172        Box::pin(async move {
173            let mut bytes = Vec::new();
174            source.read_to_end(&mut bytes).await?;
175            let mut reader = bytes.as_slice();
176            <T as Importer>::import(self, op, &mut reader, options, state)
177        })
178    }
179
180    /// Writes a set of assets to a source file format that can be read by `import`.
181    fn export<'a>(
182        &'a self,
183        output: &'a mut (dyn AsyncWrite + Unpin + Send + Sync),
184        options: &'a Self::Options,
185        state: &'a mut Self::State,
186        assets: Vec<ExportAsset>,
187    ) -> BoxFuture<'a, Result<ImporterValue>> {
188        Box::pin(async move {
189            let mut write_buf = Vec::new();
190            let result = <T as Importer>::export(self, &mut write_buf, options, state, assets)?;
191            output.write(&write_buf).await?;
192            Ok(result)
193        })
194    }
195}
196
197/// Contains metadata and asset data for an imported asset.
198/// Produced by [Importer] implementations.
199pub struct ImportedAsset {
200    /// UUID for the asset to uniquely identify it.
201    pub id: AssetUuid,
202    /// Search tags are used by asset tooling to search for the imported asset.
203    pub search_tags: Vec<(String, Option<String>)>,
204    /// Build dependencies will be included in the Builder arguments when building the asset.
205    pub build_deps: Vec<AssetRef>,
206    /// Load dependencies are guaranteed to load before this asset.
207    pub load_deps: Vec<AssetRef>,
208    /// The referenced build pipeline is invoked when a build artifact is requested for the imported asset.
209    pub build_pipeline: Option<AssetUuid>,
210    /// The actual asset data used by tools and Builder.
211    pub asset_data: Box<dyn SerdeObj>,
212}
213
214/// Return value for Importers containing all imported assets.
215pub struct ImporterValue {
216    pub assets: Vec<ImportedAsset>,
217}
218
219/// Input to Importer::export
220pub struct ExportAsset {
221    /// Asset to be exported
222    pub asset: SerializedAsset<Vec<u8>>,
223}
224
225#[cfg(feature = "serde_importers")]
226#[macro_export]
227macro_rules! if_serde_importers {
228    ($($tt:tt)*) => {
229        $($tt)*
230    }
231}
232
233#[cfg(not(feature = "serde_importers"))]
234#[macro_export]
235#[doc(hidden)]
236macro_rules! if_serde_importers {
237    ($($tt:tt)*) => {};
238}
239
240/// Convenience function for reporting an error in an `Importer`
241pub fn import_error<T: Into<String>>(text: String) -> Box<dyn std::error::Error + Send + 'static> {
242    Box::new(Error::Custom(text))
243}