1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
use distill_core::TypeUuidDynamic;
use erased_serde::Deserializer;
use futures::{future::BoxFuture, AsyncRead, AsyncWrite};
use serde::{Deserialize, Serialize};

use crate::{error::Result, AsyncImporter, ExportAsset, ImportOp, ImporterValue, SerdeObj};

/// Version of the SourceMetadata struct.
/// Used for forward compatibility to enable changing the .meta file format
pub const SOURCEMETADATA_VERSION: u32 = 2;

/// SourceMetadata is the in-memory representation of the .meta file for a (source, .meta) pair.
#[derive(Serialize, Deserialize)]
pub struct SourceMetadata<Options: 'static, State: 'static> {
    /// Metadata struct version
    pub version: u32,
    /// The [`crate::Importer::Options`] used to import the source file.
    pub importer_options: Options,
    /// The [`crate::Importer::State`] generated when importing the source file.
    pub importer_state: State,
}

/// Trait object wrapper for [`crate::Importer`] implementations.
/// Enables using Importers without knowing the concrete type.
/// See [`crate::Importer`] for documentation on fields.
pub trait BoxedImporter: TypeUuidDynamic + Send + Sync + 'static {
    fn import_boxed<'a>(
        &'a self,
        op: &'a mut ImportOp,
        source: &'a mut (dyn AsyncRead + Unpin + Send + Sync),
        options: Box<dyn SerdeObj>,
        state: Box<dyn SerdeObj>,
    ) -> BoxFuture<'a, Result<BoxedImporterValue>>;
    fn export_boxed<'a>(
        &'a self,
        output: &'a mut (dyn AsyncWrite + Unpin + Send + Sync),
        options: Box<dyn SerdeObj>,
        state: Box<dyn SerdeObj>,
        assets: Vec<ExportAsset>,
    ) -> BoxFuture<'a, Result<BoxedExportInputs>>;
    fn default_options(&self) -> Box<dyn SerdeObj>;
    fn default_state(&self) -> Box<dyn SerdeObj>;
    fn version(&self) -> u32;
    fn deserialize_metadata(
        &self,
        deserializer: &mut dyn Deserializer,
    ) -> Result<SourceMetadata<Box<dyn SerdeObj>, Box<dyn SerdeObj>>>;
    fn deserialize_options(&self, deserializer: &mut dyn Deserializer)
        -> Result<Box<dyn SerdeObj>>;
    fn deserialize_state(&self, deserializer: &mut dyn Deserializer) -> Result<Box<dyn SerdeObj>>;
}

impl std::fmt::Debug for dyn BoxedImporter {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_tuple("BoxedImporter").field(&self.uuid()).finish()
    }
}

/// Trait object wrapper for [ImporterValue] implementations.
/// See [ImporterValue] for documentation on fields.
pub struct BoxedImporterValue {
    pub value: ImporterValue,
    pub options: Box<dyn SerdeObj>,
    pub state: Box<dyn SerdeObj>,
}

/// Return value for BoxedImporter::export_boxed
pub struct BoxedExportInputs {
    pub options: Box<dyn SerdeObj>,
    pub state: Box<dyn SerdeObj>,
    pub value: ImporterValue,
}

impl<S, O, T> BoxedImporter for T
where
    O: SerdeObj + Serialize + Default + Send + Sync + Clone + for<'a> Deserialize<'a>,
    S: SerdeObj + Serialize + Default + Send + Sync + for<'a> Deserialize<'a>,
    T: AsyncImporter<State = S, Options = O> + TypeUuidDynamic + Send + Sync,
{
    fn import_boxed<'a>(
        &'a self,
        op: &'a mut ImportOp,
        source: &'a mut (dyn AsyncRead + Unpin + Send + Sync),
        options: Box<dyn SerdeObj>,
        mut state: Box<dyn SerdeObj>,
    ) -> BoxFuture<'a, Result<BoxedImporterValue>> {
        log::trace!("import_boxed");
        Box::pin(async move {
            let s = state.any_mut().downcast_mut::<S>();
            let s = if let Some(s) = s {
                s
            } else {
                panic!("Failed to downcast Importer::State");
            };
            let o = options.any().downcast_ref::<O>();
            let o = if let Some(o) = o {
                o
            } else {
                panic!("Failed to downcast Importer::Options");
            };

            log::trace!("import_boxed about to import");
            let result = self.import(op, source, o, s).await?;
            log::trace!("import_boxed imported");
            Ok(BoxedImporterValue {
                value: result,
                options,
                state,
            })
        })
    }

    fn export_boxed<'a>(
        &'a self,
        output: &'a mut (dyn AsyncWrite + Unpin + Send + Sync),
        options: Box<dyn SerdeObj>,
        mut state: Box<dyn SerdeObj>,
        assets: Vec<ExportAsset>,
    ) -> BoxFuture<'a, Result<BoxedExportInputs>> {
        Box::pin(async move {
            let s = state.any_mut().downcast_mut::<S>();
            let s = if let Some(s) = s {
                s
            } else {
                panic!("Failed to downcast Importer::State");
            };
            let o = options.any().downcast_ref::<O>();
            let o = if let Some(o) = o {
                o
            } else {
                panic!("Failed to downcast Importer::Options");
            };

            let result = self.export(output, o, s, assets).await?;
            Ok(BoxedExportInputs {
                options,
                state,
                value: result,
            })
        })
    }

    fn default_options(&self) -> Box<dyn SerdeObj> {
        Box::new(O::default())
    }

    fn default_state(&self) -> Box<dyn SerdeObj> {
        Box::new(S::default())
    }

    fn version(&self) -> u32 {
        T::version(self)
    }

    fn deserialize_metadata<'a>(
        &self,
        deserializer: &mut dyn Deserializer,
    ) -> Result<SourceMetadata<Box<dyn SerdeObj>, Box<dyn SerdeObj>>> {
        let metadata = erased_serde::deserialize::<SourceMetadata<O, S>>(deserializer)?;
        Ok(SourceMetadata {
            version: metadata.version,
            importer_options: Box::new(metadata.importer_options),
            importer_state: Box::new(metadata.importer_state),
        })
    }

    fn deserialize_options<'a>(
        &self,
        deserializer: &mut dyn Deserializer,
    ) -> Result<Box<dyn SerdeObj>> {
        Ok(Box::new(erased_serde::deserialize::<O>(deserializer)?))
    }

    fn deserialize_state<'a>(
        &self,
        deserializer: &mut dyn Deserializer,
    ) -> Result<Box<dyn SerdeObj>> {
        Ok(Box::new(erased_serde::deserialize::<S>(deserializer)?))
    }
}