mewo_ecs/galaxy/
entity.rs

1use super::{
2    ComponentAccessesOptional, ComponentGroupId, Entity, Galaxy, GenericComponent, QueryAccessType,
3    StorageModifyTransform, StorageTransform,
4};
5use crate::data::TVal;
6use std::marker::PhantomData;
7
8pub trait EntityModifyOnly {}
9pub struct EntityModifyOnlyImpl;
10impl EntityModifyOnly for EntityModifyOnlyImpl {}
11
12pub struct EntityGetter<'gal, T> {
13    galaxy: &'gal Galaxy,
14    trans: Option<StorageTransform>,
15    phantom: PhantomData<T>,
16}
17
18impl<'gal, T> EntityGetter<'gal, T> {
19    pub fn get_entity(&self) -> Entity {
20        match self.trans.as_ref().unwrap() {
21            StorageTransform::Insert(e, _) | StorageTransform::Modify(e, _) => *e,
22            _ => unreachable!(),
23        }
24    }
25
26    pub fn insert<C: GenericComponent + 'static>(&mut self, c: C) -> &mut Self {
27        self.component_maybe_insert::<C>();
28        match self.trans.as_mut().unwrap() {
29            StorageTransform::Insert(_, modify) | StorageTransform::Modify(_, modify) => {
30                modify.insert(C::mewo_component_id(), unsafe {
31                    TVal::new(
32                        C::mewo_component_size(),
33                        &c as *const C as *const u8,
34                        C::mewo_component_drop(),
35                    )
36                });
37            }
38            _ => unreachable!(),
39        }
40        std::mem::forget(c);
41        self
42    }
43
44    pub fn remove<C: GenericComponent + 'static>(&mut self) -> &mut Self {
45        self.component_maybe_insert::<C>();
46        match self.trans.as_mut().unwrap() {
47            StorageTransform::Insert(_, modify) | StorageTransform::Modify(_, modify) => {
48                modify.remove(C::mewo_component_id());
49            }
50            _ => unreachable!(),
51        }
52        self
53    }
54
55    fn component_maybe_insert<C: GenericComponent + 'static>(&self) {
56        let id = C::mewo_component_id();
57        if self.galaxy.ctyp.read().get_type(id).is_err() {
58            let mut ctyp = self.galaxy.ctyp.write();
59            ctyp.insert_type(id, C::mewo_component_type_entry())
60                .unwrap();
61        }
62    }
63}
64
65impl<'gal, T> EntityGetter<'gal, T>
66where
67    T: EntityModifyOnly,
68{
69    pub fn get<CA: ComponentAccessesOptional>(
70        &mut self,
71    ) -> Option<EntityComponentGetter<'gal, CA>> {
72        Some(EntityComponentGetter::new(
73            self.galaxy,
74            *match self.trans.as_ref().unwrap() {
75                StorageTransform::Modify(e, _) => e,
76                _ => return None?,
77            },
78        ))
79    }
80}
81
82impl<'gal, T> Drop for EntityGetter<'gal, T> {
83    fn drop(&mut self) {
84        self.galaxy
85            .get_storage_transforms()
86            .push(self.trans.take().unwrap());
87    }
88}
89
90pub struct EntityComponentGetter<'gal, CA: ComponentAccessesOptional> {
91    galaxy: &'gal Galaxy,
92    group_id: ComponentGroupId,
93    entity_idx: usize,
94    datas: Vec<Option<*const u8>>,
95    phantom: PhantomData<CA>,
96}
97
98impl<'gal, CA> EntityComponentGetter<'gal, CA>
99where
100    CA: ComponentAccessesOptional,
101{
102    pub fn new(galaxy: &'gal Galaxy, entity: Entity) -> Self {
103        CA::component_maybe_insert(&galaxy.ctyp);
104        let sp = galaxy.sp.read();
105        let cgp = galaxy.cgp.read();
106        let gid = sp.get_entity_group(entity).unwrap();
107        let group = cgp.get_group(gid).unwrap();
108        let query = CA::infos();
109        let mut datas: Vec<Option<*const u8>> = query.iter().map(|_| None).collect();
110        for &cty in group.get_components() {
111            for (idx, &(qcty, qlock)) in query.iter().enumerate() {
112                if qcty == cty {
113                    match qlock {
114                        QueryAccessType::Read | QueryAccessType::OptionRead => {
115                            sp.get_read_lock(gid, cty).unwrap();
116                            *datas.get_mut(idx).unwrap() = sp.get_read(gid, cty);
117                        }
118                        QueryAccessType::Write | QueryAccessType::OptionWrite => {
119                            sp.get_write_lock(gid, cty).unwrap();
120                            *datas.get_mut(idx).unwrap() = sp.get_read(gid, cty);
121                        }
122                    };
123                }
124            }
125        }
126        EntityComponentGetter {
127            galaxy,
128            entity_idx: sp.get_entity_idx(gid, entity).unwrap(),
129            group_id: gid,
130            datas: datas.into_iter().collect(),
131            phantom: PhantomData,
132        }
133    }
134
135    pub fn get(&self) -> CA {
136        CA::datas(&self.datas, self.entity_idx)
137    }
138}
139
140impl<'gal, CA> Drop for EntityComponentGetter<'gal, CA>
141where
142    CA: ComponentAccessesOptional,
143{
144    fn drop(&mut self) {
145        let sp = self.galaxy.sp.read();
146        let cgp = self.galaxy.cgp.read();
147        let group = cgp.get_group(self.group_id).unwrap();
148        let query = CA::infos();
149
150        //  Maybe it's safer to drop locks in order?
151        for &cty in group.get_components() {
152            for &(qcty, qlock) in query.iter() {
153                if qcty == cty {
154                    match qlock {
155                        //  Some(whatever.unwrap()) is intentional.
156                        QueryAccessType::Read | QueryAccessType::OptionRead => {
157                            sp.get_read_unlock(self.group_id, cty).unwrap()
158                        }
159                        QueryAccessType::Write | QueryAccessType::OptionWrite => {
160                            sp.get_write_unlock(self.group_id, cty).unwrap()
161                        }
162                    };
163                }
164            }
165        }
166    }
167}
168
169impl Galaxy {
170    pub fn insert_entity(&self) -> EntityGetter<()> {
171        let e = self.ep.write().insert();
172        EntityGetter {
173            galaxy: self,
174            trans: Some(StorageTransform::Insert(e, StorageModifyTransform::new())),
175            phantom: PhantomData,
176        }
177    }
178
179    pub fn get_entity(&self, entity: Entity) -> Option<EntityGetter<EntityModifyOnlyImpl>> {
180        self.ep.read().has_entity(entity).then_some(EntityGetter {
181            galaxy: self,
182            trans: Some(StorageTransform::Modify(
183                entity,
184                StorageModifyTransform::new(),
185            )),
186            phantom: PhantomData,
187        })
188    }
189
190    pub fn remove_entity(&self, e: Entity) {
191        self.get_storage_transforms()
192            .push(StorageTransform::Remove(e));
193    }
194
195    pub fn get_entities(&self) -> Vec<Entity> {
196        self.ep.read().get_entities()
197    }
198}