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
pub mod artifact_storage;
mod disk_io;
pub mod loader;
pub mod storage;

pub use crate::artifact_storage::{ArtifactStorageSet, DynArtifactLoader};
use crate::disk_io::DiskArtifactIO;
use crate::loader::Loader;
use crossbeam_channel::{Receiver, Sender};
use hydrate_base::handle::RefOp;
use hydrate_base::{ArtifactId, StringHash};
use std::path::PathBuf;
use type_uuid::TypeUuid;

mod artifact_type_id;
pub use artifact_type_id::ArtifactTypeId;

use crate::storage::IndirectIdentifier;
pub use hydrate_base::handle::Handle;

pub fn process_ref_ops(
    loader: &Loader,
    rx: &Receiver<RefOp>,
) {
    while let Ok(ref_op) = rx.try_recv() {
        match ref_op {
            RefOp::Decrease(handle) => loader.remove_engine_ref(handle),
            RefOp::Increase(handle) => {
                loader.add_engine_ref_by_handle(handle);
            }
        }
    }
}

pub struct ArtifactManager {
    artifact_storage: ArtifactStorageSet,
    loader: Loader,
    ref_op_tx: Sender<RefOp>,
    ref_op_rx: Receiver<RefOp>,
}

impl ArtifactManager {
    pub fn new(build_data_root_path: PathBuf) -> Result<Self, String> {
        let (ref_op_tx, ref_op_rx) = crossbeam_channel::unbounded();
        let (loader_events_tx, loader_events_rx) = crossbeam_channel::unbounded();

        let artifact_io = DiskArtifactIO::new(build_data_root_path, loader_events_tx.clone())?;
        let loader = Loader::new(Box::new(artifact_io), loader_events_tx, loader_events_rx);
        let artifact_storage = ArtifactStorageSet::new(ref_op_tx.clone());

        let mut loader = ArtifactManager {
            artifact_storage,
            loader,
            ref_op_tx,
            ref_op_rx,
        };

        loader.update();

        Ok(loader)
    }

    pub fn loader(&self) -> &Loader {
        &self.loader
    }

    pub fn storage(&self) -> &ArtifactStorageSet {
        &self.artifact_storage
    }

    pub fn add_storage<T>(&mut self)
    where
        T: TypeUuid + for<'a> serde::Deserialize<'a> + 'static + Send,
    {
        self.artifact_storage.add_storage::<T>();
    }

    pub fn add_storage_with_loader<ArtifactDataT, ArtifactT, LoaderT>(
        &mut self,
        loader: Box<LoaderT>,
    ) where
        ArtifactDataT: TypeUuid + for<'a> serde::Deserialize<'a> + 'static,
        ArtifactT: TypeUuid + 'static + Send,
        LoaderT: DynArtifactLoader<ArtifactT> + 'static,
    {
        self.artifact_storage
            .add_storage_with_loader::<ArtifactDataT, ArtifactT, LoaderT>(loader);
    }

    pub fn load_artifact<T: TypeUuid + 'static + Send>(
        &self,
        artifact_id: ArtifactId,
    ) -> Handle<T> {
        let data_type_uuid = self
            .storage()
            .artifact_to_data_type_uuid::<T>()
            .expect("Called load_artifact with unregistered asset type");
        let load_handle = self
            .loader
            .add_engine_ref_indirect(IndirectIdentifier::ArtifactId(artifact_id, data_type_uuid));
        Handle::<T>::new(self.ref_op_tx.clone(), load_handle)
    }

    pub fn load_artifact_symbol_name<T: TypeUuid + 'static + Send>(
        &self,
        symbol_name: &'static str,
    ) -> Handle<T> {
        self.load_artifact_symbol_string_hash(StringHash::from_static_str(symbol_name))
    }

    pub fn load_artifact_symbol_string_hash<T: TypeUuid + 'static + Send>(
        &self,
        symbol: StringHash,
    ) -> Handle<T> {
        let data_type_uuid = self
            .storage()
            .artifact_to_data_type_uuid::<T>()
            .expect("Called load_artifact with unregistered asset type");

        let load_handle = self
            .loader
            .add_engine_ref_indirect(IndirectIdentifier::SymbolWithType(symbol, data_type_uuid));
        Handle::<T>::new(self.ref_op_tx.clone(), load_handle)
    }

    pub fn update(&mut self) {
        process_ref_ops(&self.loader, &self.ref_op_rx);
        self.loader.update(&mut self.artifact_storage);
    }
}