hydrate_pipeline/thumbnails/
mod.rs

1mod thumbnail_provider_registry;
2pub use thumbnail_provider_registry::*;
3
4mod thumbnail_types;
5pub use thumbnail_types::*;
6
7mod thumbnail_system;
8mod thumbnail_thread_pool;
9
10pub use thumbnail_system::ThumbnailImage;
11pub use thumbnail_system::ThumbnailSystem;
12pub use thumbnail_system::ThumbnailSystemState;
13
14use crate::build::FetchedImportData;
15use crate::PipelineResult;
16use hydrate_base::hashing::HashMap;
17use hydrate_base::AssetId;
18use hydrate_data::{DataSet, SchemaSet};
19use hydrate_schema::HashSet;
20use siphasher::sip128::Hasher128;
21use std::cell::RefCell;
22use std::hash::Hash;
23use std::rc::Rc;
24use std::sync::Arc;
25
26crate::create_uuid_newtype!(ThumbnailInputHash, "ThumbnailInputHash");
27
28#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
29pub struct ThumbnailProviderId(pub usize);
30
31pub struct ThumbnailEnumeratedDependencies {
32    // This hash will include things like import data hash
33    pub(crate) thumbnail_input_hash: ThumbnailInputHash,
34    pub(crate) gathered_data: Arc<Vec<u8>>,
35}
36
37pub trait ThumbnailProviderAbstract: Send + Sync {
38    // The type of asset that this builder handles
39    fn asset_type_inner(&self) -> &'static str;
40
41    fn version_inner(&self) -> u32;
42
43    fn gather_inner(
44        &self,
45        asset_id: AssetId,
46        data_set: &DataSet,
47        schema_set: &SchemaSet,
48    ) -> PipelineResult<ThumbnailEnumeratedDependencies>;
49
50    fn render_inner(
51        &self,
52        asset_id: AssetId,
53        gathered_data: &Vec<u8>,
54        schema_set: &SchemaSet,
55        thumbnail_api: &ThumbnailApi,
56    ) -> PipelineResult<ThumbnailImage>;
57}
58
59struct ThumbnailProviderWrapper<T: ThumbnailProvider>(T);
60
61impl<T: ThumbnailProvider + Send + Sync> ThumbnailProviderAbstract for ThumbnailProviderWrapper<T>
62where
63    <T as ThumbnailProvider>::GatheredDataT:
64        Hash + for<'a> serde::Deserialize<'a> + serde::Serialize,
65{
66    fn asset_type_inner(&self) -> &'static str {
67        self.0.asset_type()
68    }
69
70    fn version_inner(&self) -> u32 {
71        self.0.version()
72    }
73
74    fn gather_inner(
75        &self,
76        asset_id: AssetId,
77        data_set: &DataSet,
78        schema_set: &SchemaSet,
79    ) -> PipelineResult<ThumbnailEnumeratedDependencies> {
80        let mut import_data = HashSet::default();
81        let gathered_data = self.0.gather(ThumbnailProviderGatherContext {
82            asset_id,
83            data_set,
84            schema_set,
85            import_data_dependencies: &Rc::new(RefCell::new(&mut import_data)),
86        });
87
88        let mut hasher = siphasher::sip128::SipHasher::default();
89        gathered_data.hash(&mut hasher);
90        let mut thumbnail_input_hash = hasher.finish128().as_u128();
91
92        // Has the import data with xor because we don't have deterministic ordering of asset IDs
93        for asset_id in &import_data {
94            let mut hasher_inner = siphasher::sip128::SipHasher::default();
95            asset_id.hash(&mut hasher_inner);
96            if let Some(import_data) = data_set.import_info(*asset_id) {
97                import_data
98                    .import_data_contents_hash()
99                    .hash(&mut hasher_inner);
100            }
101
102            thumbnail_input_hash ^= hasher_inner.finish128().as_u128();
103        }
104
105        let gathered_data = Arc::new(bincode::serialize(&gathered_data)?);
106
107        let thumbnail_input_hash = ThumbnailInputHash::from_u128(thumbnail_input_hash);
108        Ok(ThumbnailEnumeratedDependencies {
109            thumbnail_input_hash,
110            gathered_data,
111        })
112    }
113
114    fn render_inner(
115        &self,
116        asset_id: AssetId,
117        gathered_data: &Vec<u8>,
118        schema_set: &SchemaSet,
119        thumbnail_api: &ThumbnailApi,
120    ) -> PipelineResult<ThumbnailImage> {
121        let gathered_data: T::GatheredDataT = bincode::deserialize(&*gathered_data)?;
122        let mut fetched_import_data = HashMap::<AssetId, FetchedImportData>::default();
123        self.0.render(
124            &ThumbnailProviderRenderContext {
125                desired_thumbnail_width: 256,
126                desired_thumbnail_height: 256,
127                asset_id,
128                schema_set,
129                fetched_import_data: &Rc::new(RefCell::new(&mut fetched_import_data)),
130                thumbnail_api: thumbnail_api,
131            },
132            gathered_data,
133        )
134    }
135}