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
mod handle;
mod managed;

use std::{collections::HashMap, path::Path};

pub use handle::Handle;
use refs::Own;

use crate::misc::hash;

pub type DataStorage<T> = HashMap<u64, Own<T>>;

pub trait Managed: 'static + ResourceLoader + DataManager<Self> {}

pub trait ResourceLoader: Sized {
    fn load_path(path: &Path) -> Self;
    fn load_data(data: &[u8], name: impl ToString) -> Self;
}

pub trait DataManager<T: Managed> {
    fn root_path() -> &'static Path;
    fn set_root_path(path: &Path);

    fn storage() -> &'static mut DataStorage<T>;

    fn add_with_name(name: impl ToString, resource: T) -> Handle<T> {
        Self::add_with_hash(hash(name.to_string()), resource)
    }

    fn add_with_hash(hash: u64, resource: T) -> Handle<T> {
        let storage = Self::storage();
        debug_assert!(
            !storage.contains_key(&hash),
            "Object with such hash already exists"
        );
        storage.insert(hash, Own::new(resource));
        hash.into()
    }

    fn handle_with_name(name: impl ToString) -> Option<Handle<T>> {
        Self::handle_with_hash(hash(name.to_string()))
    }

    fn handle_with_hash(hash: u64) -> Option<Handle<T>> {
        if Self::storage().contains_key(&hash) {
            Some(hash.into())
        } else {
            None
        }
    }

    fn remove_with_name(name: impl ToString) {
        Self::remove_with_hash(hash(name.to_string()))
    }

    fn remove_with_hash(hash: u64) {
        Self::storage().remove(&hash);
    }

    fn get_ref_by_hash(hash: u64) -> &'static T {
        Self::storage().get(&hash).unwrap()
    }

    fn get_ref_by_hash_mut(hash: u64) -> &'static mut T {
        Self::storage().get_mut(&hash).unwrap()
    }

    fn get(name: impl ToString) -> Handle<T> {
        let name = name.to_string();
        let hash = hash(&name);
        Self::storage()
            .entry(hash)
            .or_insert_with(|| Own::new(T::load_path(&Self::root_path().join(name))));
        hash.into()
    }

    fn load(data: &[u8], name: impl ToString) -> Handle<T> {
        let name = name.to_string();
        let hash = hash(&name);
        Self::storage()
            .entry(hash)
            .or_insert_with(|| Own::new(T::load_data(data, name)));
        hash.into()
    }
}