Skip to main content

gled_model/
asset.rs

1pub mod animation;
2pub mod curve;
3pub mod group;
4pub mod midi_controller;
5pub mod output_device;
6pub mod palette;
7pub mod project;
8pub mod scene;
9pub mod svg;
10
11use crate::asset_id::AssetId;
12use crate::collection::Collections;
13use serde::{Deserialize, Serialize, de::DeserializeOwned};
14use std::{fmt::Debug, io::Read, sync::Arc};
15
16pub trait AssetTrait:
17    Serialize + DeserializeOwned + Debug + Default + Send + Sync + Clone + 'static + PartialEq
18{
19    const DIR_NAME: &'static str;
20    const NAME: &'static str;
21    const SHOW_NAME_IF_SELECTED: bool;
22}
23
24#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
25#[serde(bound = "T: DeserializeOwned + Serialize")]
26struct AssetOnDisk<T: AssetTrait> {
27    name: Vec<String>,
28    #[serde(flatten)]
29    data: T,
30}
31
32/// An asset with its id. Serialized as such for the wire; files on disk use
33/// `AssetOnDisk`, which takes the id from the file name.
34#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
35#[serde(bound = "T: DeserializeOwned + Serialize")]
36pub struct Asset<T: AssetTrait> {
37    pub id: AssetId<T>,
38    pub path: Vec<String>,
39    pub data: T,
40}
41
42impl<T: AssetTrait> Default for Asset<T> {
43    fn default() -> Self {
44        Self::new(vec![format!("New {}", T::NAME)])
45    }
46}
47
48impl<T: AssetTrait> Asset<T> {
49    pub fn new(path: Vec<String>) -> Self {
50        Self {
51            id: AssetId::<T>::new(),
52            path,
53            data: T::default(),
54        }
55    }
56
57    /// Create a copy of an asset with a new uuid
58    pub fn copy(&self) -> Self {
59        Self {
60            id: AssetId::<T>::new(),
61            path: self.path.clone(),
62            data: self.data.clone(),
63        }
64    }
65
66    pub fn get(id: AssetId<T>, collections: &Collections) -> Option<Arc<Self>> {
67        collections.get::<T>()?.get(&id).cloned()
68    }
69
70    pub fn get_asset_from_index(index: usize, collections: &Collections) -> Option<Arc<Self>> {
71        match index {
72            0 => None,
73            index => Self::all(collections).get(index - 1).cloned(),
74        }
75    }
76
77    pub fn all(collections: &Collections) -> Vec<Arc<Asset<T>>> {
78        let Some(collections) = collections.get::<T>() else {
79            return vec![];
80        };
81
82        collections.assets()
83    }
84
85    /// Reads an asset from its JSON file.
86    pub fn read(reader: impl Read, id: AssetId<T>) -> Result<Arc<Self>, serde_json::Error> {
87        let asset: AssetOnDisk<T> = serde_json::from_reader(reader)?;
88
89        Ok(Arc::new(Self {
90            id,
91            path: asset.name,
92            data: asset.data,
93        }))
94    }
95
96    pub fn into_json(self) -> Result<String, serde_json::Error> {
97        let asset = AssetOnDisk {
98            name: self.path,
99            data: self.data,
100        };
101
102        serde_json::to_string_pretty(&asset)
103    }
104
105    pub fn dir(&self) -> Vec<String> {
106        self.path[..self.path.len() - 1].to_owned()
107    }
108
109    pub fn name(&self) -> &str {
110        self.path
111            .last()
112            .map(|name| name.as_str())
113            .unwrap_or("No name")
114    }
115
116    pub fn change_dir(&mut self, new_dir: &[String]) {
117        let name = self.path.pop();
118        self.path = new_dir.to_owned();
119        if let Some(name) = name {
120            self.path.push(name);
121        }
122    }
123}