goud_engine/component_ops/
single_ops.rs1use std::collections::HashMap;
7
8use crate::context_registry::{get_context_registry, GoudContextId, GOUD_INVALID_CONTEXT_ID};
9use crate::core::error::{set_last_error, GoudError};
10use crate::core::types::{GoudEntityId, GoudResult};
11
12use super::helpers::{context_key, entity_from_ffi};
13use super::storage::{
14 get_component_type_info, get_context_storage_map, register_component_type_internal,
15};
16
17pub unsafe fn component_register_type_impl(
25 type_id_hash: u64,
26 name_ptr: *const u8,
27 name_len: usize,
28 size: usize,
29 align: usize,
30) -> bool {
31 if name_ptr.is_null() {
32 set_last_error(GoudError::InvalidState(
33 "Component type name pointer is null".to_string(),
34 ));
35 return false;
36 }
37
38 let name_slice = std::slice::from_raw_parts(name_ptr, name_len);
41 if std::str::from_utf8(name_slice).is_err() {
42 set_last_error(GoudError::InvalidState(
43 "Component type name is not valid UTF-8".to_string(),
44 ));
45 return false;
46 }
47
48 register_component_type_internal(type_id_hash, size, align)
49}
50
51pub unsafe fn component_add_impl(
58 context_id: GoudContextId,
59 entity_id: GoudEntityId,
60 type_id_hash: u64,
61 data_ptr: *const u8,
62 data_size: usize,
63) -> GoudResult {
64 if data_ptr.is_null() {
65 return GoudResult::from_error(GoudError::InvalidState(
66 "Component data pointer is null".to_string(),
67 ));
68 }
69
70 let type_info = match get_component_type_info(type_id_hash) {
71 Some(info) => info,
72 None => {
73 return GoudResult::from_error(GoudError::ResourceLoadFailed(format!(
74 "Component type {} not registered",
75 type_id_hash
76 )));
77 }
78 };
79
80 if data_size != type_info.size {
81 return GoudResult::from_error(GoudError::InvalidState(format!(
82 "Component data size mismatch: expected {}, got {}",
83 type_info.size, data_size
84 )));
85 }
86
87 if context_id == GOUD_INVALID_CONTEXT_ID {
88 return GoudResult::from_error(GoudError::InvalidContext);
89 }
90
91 {
92 let registry = get_context_registry().lock().unwrap();
93 let context = match registry.get(context_id) {
94 Some(ctx) => ctx,
95 None => {
96 return GoudResult::from_error(GoudError::InvalidContext);
97 }
98 };
99
100 let entity = entity_from_ffi(entity_id);
101 if !context.world().is_alive(entity) {
102 return GoudResult::from_error(GoudError::EntityNotFound);
103 }
104 }
105
106 let mut storage_map = get_context_storage_map();
107 let map = storage_map.get_or_insert_with(HashMap::new);
108
109 let key = context_key(context_id);
110 let context_storage = map.entry(key).or_default();
111 let storage =
112 context_storage.get_or_create_storage(type_id_hash, type_info.size, type_info.align);
113
114 if storage.insert(entity_id.bits(), data_ptr) {
115 GoudResult::ok()
116 } else {
117 GoudResult::from_error(GoudError::InternalError(
118 "Failed to allocate component storage".to_string(),
119 ))
120 }
121}
122
123pub fn component_remove_impl(
125 context_id: GoudContextId,
126 entity_id: GoudEntityId,
127 type_id_hash: u64,
128) -> GoudResult {
129 if get_component_type_info(type_id_hash).is_none() {
130 return GoudResult::from_error(GoudError::ResourceLoadFailed(format!(
131 "Component type {} not registered",
132 type_id_hash
133 )));
134 }
135
136 if context_id == GOUD_INVALID_CONTEXT_ID {
137 return GoudResult::from_error(GoudError::InvalidContext);
138 }
139
140 {
141 let registry = get_context_registry().lock().unwrap();
142 let context = match registry.get(context_id) {
143 Some(ctx) => ctx,
144 None => {
145 return GoudResult::from_error(GoudError::InvalidContext);
146 }
147 };
148
149 let entity = entity_from_ffi(entity_id);
150 if !context.world().is_alive(entity) {
151 return GoudResult::from_error(GoudError::EntityNotFound);
152 }
153 }
154
155 let mut storage_map = get_context_storage_map();
156 let map = match storage_map.as_mut() {
157 Some(m) => m,
158 None => return GoudResult::ok(),
159 };
160
161 let key = context_key(context_id);
162 let context_storage = match map.get_mut(&key) {
163 Some(s) => s,
164 None => return GoudResult::ok(),
165 };
166
167 let storage = match context_storage.get_storage_mut(type_id_hash) {
168 Some(s) => s,
169 None => return GoudResult::ok(),
170 };
171
172 storage.remove(entity_id.bits());
173 GoudResult::ok()
174}
175
176pub fn component_has_impl(
178 context_id: GoudContextId,
179 entity_id: GoudEntityId,
180 type_id_hash: u64,
181) -> bool {
182 if get_component_type_info(type_id_hash).is_none() {
183 set_last_error(GoudError::ResourceLoadFailed(format!(
184 "Component type {} not registered",
185 type_id_hash
186 )));
187 return false;
188 }
189
190 if context_id == GOUD_INVALID_CONTEXT_ID {
191 set_last_error(GoudError::InvalidContext);
192 return false;
193 }
194
195 {
196 let registry = get_context_registry().lock().unwrap();
197 let context = match registry.get(context_id) {
198 Some(ctx) => ctx,
199 None => {
200 set_last_error(GoudError::InvalidContext);
201 return false;
202 }
203 };
204
205 let entity = entity_from_ffi(entity_id);
206 if !context.world().is_alive(entity) {
207 return false;
208 }
209 }
210
211 let storage_map = get_context_storage_map();
212 let map = match storage_map.as_ref() {
213 Some(m) => m,
214 None => return false,
215 };
216
217 let key = context_key(context_id);
218 let context_storage = match map.get(&key) {
219 Some(s) => s,
220 None => return false,
221 };
222
223 let storage = match context_storage.get_storage(type_id_hash) {
224 Some(s) => s,
225 None => return false,
226 };
227
228 storage.contains(entity_id.bits())
229}
230
231pub fn component_get_impl(
233 context_id: GoudContextId,
234 entity_id: GoudEntityId,
235 type_id_hash: u64,
236) -> *const u8 {
237 if get_component_type_info(type_id_hash).is_none() {
238 set_last_error(GoudError::ResourceLoadFailed(format!(
239 "Component type {} not registered",
240 type_id_hash
241 )));
242 return std::ptr::null();
243 }
244
245 if context_id == GOUD_INVALID_CONTEXT_ID {
246 set_last_error(GoudError::InvalidContext);
247 return std::ptr::null();
248 }
249
250 {
251 let registry = get_context_registry().lock().unwrap();
252 let context = match registry.get(context_id) {
253 Some(ctx) => ctx,
254 None => {
255 set_last_error(GoudError::InvalidContext);
256 return std::ptr::null();
257 }
258 };
259
260 let entity = entity_from_ffi(entity_id);
261 if !context.world().is_alive(entity) {
262 set_last_error(GoudError::EntityNotFound);
263 return std::ptr::null();
264 }
265 }
266
267 let storage_map = get_context_storage_map();
268 let map = match storage_map.as_ref() {
269 Some(m) => m,
270 None => return std::ptr::null(),
271 };
272
273 let key = context_key(context_id);
274 let context_storage = match map.get(&key) {
275 Some(s) => s,
276 None => return std::ptr::null(),
277 };
278
279 let storage = match context_storage.get_storage(type_id_hash) {
280 Some(s) => s,
281 None => return std::ptr::null(),
282 };
283
284 storage.get(entity_id.bits())
285}
286
287pub fn component_get_mut_impl(
289 context_id: GoudContextId,
290 entity_id: GoudEntityId,
291 type_id_hash: u64,
292) -> *mut u8 {
293 if get_component_type_info(type_id_hash).is_none() {
294 set_last_error(GoudError::ResourceLoadFailed(format!(
295 "Component type {} not registered",
296 type_id_hash
297 )));
298 return std::ptr::null_mut();
299 }
300
301 if context_id == GOUD_INVALID_CONTEXT_ID {
302 set_last_error(GoudError::InvalidContext);
303 return std::ptr::null_mut();
304 }
305
306 {
307 let registry = get_context_registry().lock().unwrap();
308 let context = match registry.get(context_id) {
309 Some(ctx) => ctx,
310 None => {
311 set_last_error(GoudError::InvalidContext);
312 return std::ptr::null_mut();
313 }
314 };
315
316 let entity = entity_from_ffi(entity_id);
317 if !context.world().is_alive(entity) {
318 set_last_error(GoudError::EntityNotFound);
319 return std::ptr::null_mut();
320 }
321 }
322
323 let mut storage_map = get_context_storage_map();
324 let map = match storage_map.as_mut() {
325 Some(m) => m,
326 None => return std::ptr::null_mut(),
327 };
328
329 let key = context_key(context_id);
330 let context_storage = match map.get_mut(&key) {
331 Some(s) => s,
332 None => return std::ptr::null_mut(),
333 };
334
335 let storage = match context_storage.get_storage_mut(type_id_hash) {
336 Some(s) => s,
337 None => return std::ptr::null_mut(),
338 };
339
340 storage.get_mut(entity_id.bits())
341}