intuicio_framework_ecs/
bundle.rs

1use crate::{
2    archetype::{ArchetypeColumnInfo, ArchetypeEntityRowAccess},
3    Component,
4};
5use intuicio_core::object::{DynamicObject, TypedDynamicObject};
6use intuicio_data::{managed::DynamicManaged, type_hash::TypeHash};
7use std::alloc::dealloc;
8
9#[derive(Default)]
10pub struct DynamicBundle {
11    components: Vec<DynamicManaged>,
12}
13
14impl DynamicBundle {
15    pub fn with_component<T>(mut self, data: T) -> Result<Self, T> {
16        self.add_component(data)?;
17        Ok(self)
18    }
19
20    pub fn with_component_raw(mut self, data: DynamicManaged) -> Self {
21        self.add_component_raw(data);
22        self
23    }
24
25    pub fn add_component<T>(&mut self, data: T) -> Result<(), T> {
26        self.add_component_raw(DynamicManaged::new(data)?);
27        Ok(())
28    }
29
30    pub fn add_component_raw(&mut self, data: DynamicManaged) {
31        if let Some(index) = self
32            .components
33            .iter()
34            .position(|component| component.type_hash() == data.type_hash())
35        {
36            self.components[index] = data;
37        } else {
38            self.components.push(data);
39        }
40    }
41
42    pub fn remove_component<T>(&mut self) -> Option<T> {
43        self.remove_component_raw(TypeHash::of::<T>())?
44            .consume()
45            .ok()
46    }
47
48    pub fn remove_component_raw(&mut self, type_hash: TypeHash) -> Option<DynamicManaged> {
49        if let Some(index) = self
50            .components
51            .iter()
52            .position(|component| component.type_hash() == &type_hash)
53        {
54            Some(self.components.swap_remove(index))
55        } else {
56            None
57        }
58    }
59}
60
61pub trait BundleColumns {
62    fn columns_static() -> Vec<ArchetypeColumnInfo>;
63
64    fn columns(&self) -> Vec<ArchetypeColumnInfo> {
65        Self::columns_static()
66    }
67}
68
69impl BundleColumns for () {
70    fn columns_static() -> Vec<ArchetypeColumnInfo> {
71        vec![]
72    }
73}
74
75impl BundleColumns for Vec<ArchetypeColumnInfo> {
76    fn columns_static() -> Vec<ArchetypeColumnInfo> {
77        vec![]
78    }
79
80    fn columns(&self) -> Vec<ArchetypeColumnInfo> {
81        self.to_owned()
82    }
83}
84
85impl BundleColumns for DynamicObject {
86    fn columns_static() -> Vec<ArchetypeColumnInfo> {
87        vec![]
88    }
89
90    fn columns(&self) -> Vec<ArchetypeColumnInfo> {
91        self.property_values()
92            .map(|object| {
93                let handle = object.type_handle();
94                unsafe {
95                    ArchetypeColumnInfo::new_raw(
96                        handle.type_hash(),
97                        *handle.layout(),
98                        handle.finalizer(),
99                    )
100                }
101            })
102            .collect()
103    }
104}
105
106impl BundleColumns for TypedDynamicObject {
107    fn columns_static() -> Vec<ArchetypeColumnInfo> {
108        vec![]
109    }
110
111    fn columns(&self) -> Vec<ArchetypeColumnInfo> {
112        self.property_values()
113            .map(|object| {
114                let handle = object.type_handle();
115                unsafe {
116                    ArchetypeColumnInfo::new_raw(
117                        handle.type_hash(),
118                        *handle.layout(),
119                        handle.finalizer(),
120                    )
121                }
122            })
123            .collect()
124    }
125}
126
127impl BundleColumns for DynamicBundle {
128    fn columns_static() -> Vec<ArchetypeColumnInfo> {
129        vec![]
130    }
131
132    fn columns(&self) -> Vec<ArchetypeColumnInfo> {
133        self.components
134            .iter()
135            .map(|component| unsafe {
136                ArchetypeColumnInfo::new_raw(
137                    *component.type_hash(),
138                    *component.layout(),
139                    component.finalizer(),
140                )
141            })
142            .collect()
143    }
144}
145
146macro_rules! impl_bundle_columns_tuple {
147    ($($type:ident),+) => {
148        impl<$($type: Component),+> BundleColumns for ($($type,)+) {
149            fn columns_static() -> Vec<ArchetypeColumnInfo> {
150                vec![$(ArchetypeColumnInfo::new::<$type>()),+]
151            }
152        }
153    };
154}
155
156impl_bundle_columns_tuple!(A);
157impl_bundle_columns_tuple!(A, B);
158impl_bundle_columns_tuple!(A, B, C);
159impl_bundle_columns_tuple!(A, B, C, D);
160impl_bundle_columns_tuple!(A, B, C, D, E);
161impl_bundle_columns_tuple!(A, B, C, D, E, F);
162impl_bundle_columns_tuple!(A, B, C, D, E, F, G);
163impl_bundle_columns_tuple!(A, B, C, D, E, F, G, H);
164impl_bundle_columns_tuple!(A, B, C, D, E, F, G, H, I);
165impl_bundle_columns_tuple!(A, B, C, D, E, F, G, H, I, J);
166impl_bundle_columns_tuple!(A, B, C, D, E, F, G, H, I, J, K);
167impl_bundle_columns_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);
168impl_bundle_columns_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M);
169impl_bundle_columns_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
170impl_bundle_columns_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
171impl_bundle_columns_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
172
173pub trait Bundle: BundleColumns {
174    fn initialize_into(self, access: &ArchetypeEntityRowAccess);
175}
176
177impl Bundle for () {
178    fn initialize_into(self, _: &ArchetypeEntityRowAccess) {}
179}
180
181impl Bundle for DynamicObject {
182    fn initialize_into(mut self, access: &ArchetypeEntityRowAccess) {
183        for (_, object) in self.drain() {
184            unsafe {
185                let (handle, source_memory) = object.into_inner();
186                let target_memory = access.data(handle.type_hash()).unwrap();
187                target_memory.copy_from(source_memory, handle.layout().size());
188                dealloc(source_memory, *handle.layout());
189            }
190        }
191    }
192}
193
194impl Bundle for TypedDynamicObject {
195    fn initialize_into(mut self, access: &ArchetypeEntityRowAccess) {
196        for (_, object) in self.drain() {
197            unsafe {
198                let (handle, source_memory) = object.into_inner();
199                let target_memory = access.data(handle.type_hash()).unwrap();
200                target_memory.copy_from(source_memory, handle.layout().size());
201                dealloc(source_memory, *handle.layout());
202            }
203        }
204    }
205}
206
207impl Bundle for DynamicBundle {
208    fn initialize_into(self, access: &ArchetypeEntityRowAccess) {
209        for component in self.components {
210            unsafe {
211                let (type_hash, _, source_memory, layout, _) = component.into_inner();
212                let target_memory = access.data(type_hash).unwrap();
213                target_memory.copy_from(source_memory, layout.size());
214                dealloc(source_memory, layout);
215            }
216        }
217    }
218}
219
220macro_rules! impl_bundle_tuple {
221    ($($type:ident),+) => {
222        impl<$($type: Component),+> Bundle for ($($type,)+) {
223            fn initialize_into(self, access: &ArchetypeEntityRowAccess) {
224                #[allow(non_snake_case)]
225                let ($($type,)+) = self;
226                $(
227                    unsafe { access.initialize($type).unwrap(); };
228                )+
229            }
230        }
231    };
232}
233
234impl_bundle_tuple!(A);
235impl_bundle_tuple!(A, B);
236impl_bundle_tuple!(A, B, C);
237impl_bundle_tuple!(A, B, C, D);
238impl_bundle_tuple!(A, B, C, D, E);
239impl_bundle_tuple!(A, B, C, D, E, F);
240impl_bundle_tuple!(A, B, C, D, E, F, G);
241impl_bundle_tuple!(A, B, C, D, E, F, G, H);
242impl_bundle_tuple!(A, B, C, D, E, F, G, H, I);
243impl_bundle_tuple!(A, B, C, D, E, F, G, H, I, J);
244impl_bundle_tuple!(A, B, C, D, E, F, G, H, I, J, K);
245impl_bundle_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);
246impl_bundle_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M);
247impl_bundle_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
248impl_bundle_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
249impl_bundle_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
250
251pub struct BundleChain<A: Bundle, B: Bundle>(pub A, pub B);
252
253impl<A: Bundle, B: Bundle> BundleColumns for BundleChain<A, B> {
254    fn columns_static() -> Vec<ArchetypeColumnInfo> {
255        let mut result = A::columns_static();
256        result.extend(B::columns_static());
257        result
258    }
259}
260
261impl<A: Bundle, B: Bundle> Bundle for BundleChain<A, B> {
262    fn initialize_into(self, access: &ArchetypeEntityRowAccess) {
263        self.0.initialize_into(access);
264        self.1.initialize_into(access);
265    }
266}