hydrate_model/editor/
location_cache.rs

1use crate::{AssetPath, EditorModel};
2use hydrate_base::hashing::HashMap;
3use hydrate_base::AssetId;
4use hydrate_data::DataSet;
5use hydrate_schema::{DataSetResult, SchemaNamedType};
6
7pub fn build_path_lookup(
8    data_set: &DataSet,
9    path_node_type: &SchemaNamedType,
10    path_node_root_type: &SchemaNamedType,
11) -> DataSetResult<HashMap<AssetId, AssetPath>> {
12    let mut paths = HashMap::<AssetId, AssetPath>::default();
13    for (asset_id, info) in data_set.assets() {
14        if info.schema().fingerprint() == path_node_root_type.fingerprint() {
15            // Special case for path node roots
16            if let Some(name) = info.asset_name().as_string() {
17                paths.insert(*asset_id, AssetPath::new_root(name));
18            }
19        } else {
20            // For assets that *are* path nodes, use their ID directly. For assets that aren't
21            // path nodes, use their location asset ID
22            let path_node_id = if info.schema().fingerprint() == path_node_type.fingerprint()
23                || info.schema().fingerprint() == path_node_root_type.fingerprint()
24            {
25                *asset_id
26            } else {
27                // We could process assets so that if for some reason the parent nodes don't exist, we can still
28                // generate path lookups for them. Instead we will consider a parent not being found as
29                // the asset being at the root level. We could also have a "lost and found" UI.
30                //info.asset_location().path_node_id()
31                continue;
32            };
33
34            // We will walk up the location chain and cache the path_node_id/path pairs. (We resolve
35            // the parents recursively going all the way up to the root, and then appending the
36            // current node to it's parent's resolved path.)
37            let mut chain = data_set.asset_location_chain(path_node_id)?;
38            if !chain.is_empty() {
39                let name = data_set.asset_name(chain.pop().unwrap().path_node_id())?;
40                if let Some(name) = name.as_string() {
41                    let mut asset_path = AssetPath::new_root(name);
42
43                    let mut path_is_valid = true;
44                    for i in (0..chain.len()).rev() {
45                        let name = data_set.asset_name(chain[i].path_node_id())?;
46                        if let Some(name) = name.as_string() {
47                            asset_path = asset_path.join(name);
48                        } else {
49                            path_is_valid = false;
50                            break;
51                        }
52                    }
53
54                    if path_is_valid {
55                        let name = data_set.asset_name(*asset_id)?;
56                        if let Some(name) = name.as_string() {
57                            asset_path = asset_path.join(name);
58                            paths.insert(*asset_id, asset_path);
59                        }
60                    }
61                }
62            }
63        }
64    }
65
66    Ok(paths)
67}
68
69pub struct AssetPathCache {
70    path_to_id_lookup: HashMap<AssetId, AssetPath>,
71}
72
73impl AssetPathCache {
74    pub fn empty() -> Self {
75        AssetPathCache {
76            path_to_id_lookup: Default::default(),
77        }
78    }
79
80    pub fn build(editor_model: &EditorModel) -> DataSetResult<Self> {
81        let path_to_id_lookup = build_path_lookup(
82            editor_model.root_edit_context().data_set(),
83            editor_model.path_node_schema(),
84            editor_model.path_node_root_schema(),
85        )?;
86
87        Ok(AssetPathCache { path_to_id_lookup })
88    }
89
90    pub fn path_to_id_lookup(&self) -> &HashMap<AssetId, AssetPath> {
91        &self.path_to_id_lookup
92    }
93}