1use std::sync::Arc;
6
7use gled_model::{
8 asset::{
9 Asset, AssetTrait, animation::Animation, curve::Curve, midi_controller::MidiController,
10 output_device::OutputDevice, palette::Palette, project::Project, scene::Scene,
11 },
12 asset_id::AssetId,
13 collection::{Collection, Collections},
14};
15use serde::{Deserialize, Serialize};
16
17#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
19pub struct AssetChanges {
20 pub changed: Vec<AnyAsset>,
22 pub deleted: Vec<AnyAssetId>,
23}
24
25impl AssetChanges {
26 pub fn is_empty(&self) -> bool {
27 self.changed.is_empty() && self.deleted.is_empty()
28 }
29
30 pub fn apply_to(self, collections: &mut Collections) {
32 for asset in self.changed {
33 asset.insert_into(collections);
34 }
35 for id in self.deleted {
36 id.remove_from(collections);
37 }
38 }
39}
40
41pub fn collections_from(assets: Vec<AnyAsset>) -> Collections {
43 let mut collections = Collections::default();
44 for asset in assets {
45 asset.insert_into(&mut collections);
46 }
47 collections
48}
49
50fn diff_kind<T: AssetTrait>(
54 old: &Collections,
55 new: &Collections,
56 changes: &mut AssetChanges,
57 wrap: fn(Arc<Asset<T>>) -> AnyAsset,
58 wrap_id: fn(AssetId<T>) -> AnyAssetId,
59) {
60 let empty = Collection::<T>::default();
61 let old = old.get::<T>().unwrap_or(&empty);
62 let new = new.get::<T>().unwrap_or(&empty);
63 for asset in new.shared() {
64 let unchanged = old
65 .get(&asset.id)
66 .is_some_and(|previous| Arc::ptr_eq(previous, asset) || previous == asset);
67 if !unchanged {
68 changes.changed.push(wrap(asset.clone()));
69 }
70 }
71 for asset in old.shared() {
72 if new.get(&asset.id).is_none() {
73 changes.deleted.push(wrap_id(asset.id));
74 }
75 }
76}
77
78pub trait KnownAsset: AssetTrait {
80 fn wrap(asset: Arc<Asset<Self>>) -> AnyAsset;
81 fn wrap_id(id: AssetId<Self>) -> AnyAssetId;
82}
83
84pub trait AssetVisitor {
86 fn asset<T: AssetTrait>(&mut self, asset: Arc<Asset<T>>);
87}
88
89pub trait AssetIdVisitor {
91 fn id<T: AssetTrait>(&mut self, id: AssetId<T>);
92}
93
94macro_rules! asset_kinds {
96 ($($kind:ident),* $(,)?) => {
97 #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
99 pub enum AnyAsset {
100 $($kind(Arc<Asset<$kind>>),)*
101 }
102
103 #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
105 pub enum AnyAssetId {
106 $($kind(AssetId<$kind>),)*
107 }
108
109 impl AnyAsset {
110 pub fn id(&self) -> AnyAssetId {
111 match self {
112 $(Self::$kind(asset) => AnyAssetId::$kind(asset.id),)*
113 }
114 }
115
116 pub fn accept(self, visitor: &mut impl AssetVisitor) {
117 match self {
118 $(Self::$kind(asset) => visitor.asset(asset),)*
119 }
120 }
121
122 pub(crate) fn insert_into(self, collections: &mut Collections) {
123 match self {
124 $(Self::$kind(asset) => collections.get_mut::<$kind>().insert_shared(asset),)*
125 }
126 }
127 }
128
129 impl AnyAssetId {
130 pub fn accept(self, visitor: &mut impl AssetIdVisitor) {
131 match self {
132 $(Self::$kind(id) => visitor.id(id),)*
133 }
134 }
135
136 pub(crate) fn remove_from(self, collections: &mut Collections) {
137 match self {
138 $(Self::$kind(id) => collections.get_mut::<$kind>().delete_asset(id),)*
139 }
140 }
141 }
142
143 $(
144 impl KnownAsset for $kind {
145 fn wrap(asset: Arc<Asset<Self>>) -> AnyAsset {
146 AnyAsset::$kind(asset)
147 }
148
149 fn wrap_id(id: AssetId<Self>) -> AnyAssetId {
150 AnyAssetId::$kind(id)
151 }
152 }
153 )*
154
155 pub fn all_assets(collections: &Collections) -> Vec<AnyAsset> {
157 let mut assets = Vec::new();
158 $(
159 if let Some(collection) = collections.get::<$kind>() {
160 assets.extend(collection.shared().cloned().map(AnyAsset::$kind));
161 }
162 )*
163 assets
164 }
165
166 impl AssetChanges {
167 pub fn between(old: &Collections, new: &Collections) -> Self {
169 let mut changes = Self::default();
170 $(diff_kind::<$kind>(old, new, &mut changes, AnyAsset::$kind, AnyAssetId::$kind);)*
171 changes
172 }
173 }
174 };
175}
176
177asset_kinds!(
178 Animation,
179 Curve,
180 MidiController,
181 OutputDevice,
182 Palette,
183 Project,
184 Scene,
185);