1use std::any::Any;
9use std::{any, fmt};
10
11#[cfg(all(since_api = "4.3", feature = "register-docs"))] #[cfg_attr(published_docs, doc(cfg(all(since_api = "4.3", feature = "register-docs"))))]
12use crate::docs::*;
13use crate::init::InitLevel;
14use crate::meta::ClassName;
15use crate::obj::{bounds, cap, Bounds, DynGd, Gd, GodotClass, Inherits, UserClass};
16use crate::registry::callbacks;
17use crate::registry::class::GodotGetVirtual;
18use crate::{classes, sys};
19
20#[derive(Debug)]
30pub struct ClassPlugin {
31 pub(crate) class_name: ClassName,
36
37 pub(crate) init_level: InitLevel,
43
44 pub(crate) item: PluginItem,
46}
47
48impl ClassPlugin {
49 pub fn new<T: GodotClass>(item: PluginItem) -> Self {
51 Self {
52 class_name: T::class_name(),
53 init_level: T::INIT_LEVEL,
54 item,
55 }
56 }
57}
58
59#[derive(Copy, Clone)]
64pub struct ErasedRegisterFn {
65 pub raw: fn(&mut dyn Any),
70}
71
72impl fmt::Debug for ErasedRegisterFn {
73 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74 write!(f, "0x{:0>16x}", self.raw as usize)
75 }
76}
77
78#[derive(Copy, Clone)]
80pub struct ErasedRegisterRpcsFn {
81 pub raw: fn(&mut dyn Any),
88}
89
90impl fmt::Debug for ErasedRegisterRpcsFn {
91 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92 write!(f, "0x{:0>16x}", self.raw as usize)
93 }
94}
95
96pub type ErasedDynifyFn = unsafe fn(Gd<classes::Object>) -> ErasedDynGd;
100
101pub struct ErasedDynGd {
105 pub boxed: Box<dyn Any>,
106}
107
108type GodotCreateFn = unsafe extern "C" fn(
109 _class_userdata: *mut std::ffi::c_void,
110 #[cfg(since_api = "4.4")] _notify_postinitialize: sys::GDExtensionBool,
111) -> sys::GDExtensionObjectPtr;
112
113#[derive(Clone, Debug)]
121pub enum PluginItem {
122 Struct(Struct),
124
125 InherentImpl(InherentImpl),
127
128 ITraitImpl(ITraitImpl),
130
131 DynTraitImpl(DynTraitImpl),
133}
134
135fn set<T>(field: &mut Option<T>, value: T) {
137 assert!(field.is_none(), "attempted to set field more than once",);
138 *field = Some(value);
139}
140
141#[derive(Clone, Debug)]
143pub struct Struct {
144 pub(crate) base_class_name: ClassName,
148
149 pub(crate) generated_create_fn: Option<GodotCreateFn>,
157
158 pub(crate) generated_recreate_fn: Option<
162 unsafe extern "C" fn(
163 p_class_userdata: *mut std::ffi::c_void,
164 p_object: sys::GDExtensionObjectPtr,
165 ) -> sys::GDExtensionClassInstancePtr,
166 >,
167
168 pub(crate) register_properties_fn: ErasedRegisterFn,
170
171 pub(crate) reference_fn: sys::GDExtensionClassReference,
173
174 pub(crate) unreference_fn: sys::GDExtensionClassUnreference,
176
177 pub(crate) free_fn: unsafe extern "C" fn(
181 _class_user_data: *mut std::ffi::c_void,
182 instance: sys::GDExtensionClassInstancePtr,
183 ),
184
185 pub(crate) default_get_virtual_fn: Option<GodotGetVirtual>,
188
189 pub(crate) is_tool: bool,
191
192 pub(crate) is_editor_plugin: bool,
194
195 pub(crate) is_internal: bool,
197
198 pub(crate) is_instantiable: bool,
200
201 #[cfg(all(since_api = "4.3", feature = "register-docs"))] #[cfg_attr(published_docs, doc(cfg(all(since_api = "4.3", feature = "register-docs"))))]
203 pub(crate) docs: StructDocs,
204}
205
206impl Struct {
207 pub fn new<T: GodotClass + cap::ImplementsGodotExports>(
208 #[cfg(all(since_api = "4.3", feature = "register-docs"))] #[cfg_attr(published_docs, doc(cfg(all(since_api = "4.3", feature = "register-docs"))))] docs: StructDocs,
209 ) -> Self {
210 let refcounted = <T::Memory as bounds::Memory>::IS_REF_COUNTED;
211
212 Self {
213 base_class_name: T::Base::class_name(),
214 generated_create_fn: None,
215 generated_recreate_fn: None,
216 register_properties_fn: ErasedRegisterFn {
217 raw: callbacks::register_user_properties::<T>,
218 },
219 free_fn: callbacks::free::<T>,
220 default_get_virtual_fn: None,
221 is_tool: false,
222 is_editor_plugin: false,
223 is_internal: false,
224 is_instantiable: false,
225 #[cfg(all(since_api = "4.3", feature = "register-docs"))] #[cfg_attr(published_docs, doc(cfg(all(since_api = "4.3", feature = "register-docs"))))]
226 docs,
227 reference_fn: refcounted.then_some(callbacks::reference::<T>),
229 unreference_fn: refcounted.then_some(callbacks::unreference::<T>),
230 }
231 }
232
233 pub fn with_generated<T: GodotClass + cap::GodotDefault>(mut self) -> Self {
234 set(&mut self.generated_create_fn, callbacks::create::<T>);
235
236 #[cfg(since_api = "4.2")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.2")))]
237 set(&mut self.generated_recreate_fn, callbacks::recreate::<T>);
238 self
239 }
240
241 #[cfg(before_api = "4.5")] #[cfg_attr(published_docs, doc(cfg(before_api = "4.5")))]
243 pub fn with_generated_no_default<T: GodotClass>(mut self) -> Self {
244 set(&mut self.generated_create_fn, callbacks::create_null::<T>);
245
246 #[cfg(since_api = "4.2")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.2")))]
247 set(
248 &mut self.generated_recreate_fn,
249 callbacks::recreate_null::<T>,
250 );
251 self
252 }
253
254 pub fn with_default_get_virtual_fn<T: GodotClass + UserClass>(mut self) -> Self {
255 set(
256 &mut self.default_get_virtual_fn,
257 callbacks::default_get_virtual::<T>,
258 );
259 self
260 }
261
262 pub fn with_tool(mut self) -> Self {
263 self.is_tool = true;
264 self
265 }
266
267 pub fn with_editor_plugin(mut self) -> Self {
268 self.is_editor_plugin = true;
269 self
270 }
271
272 pub fn with_internal(mut self) -> Self {
273 self.is_internal = true;
274 self
275 }
276
277 pub fn with_instantiable(mut self) -> Self {
278 self.is_instantiable = true;
279 self
280 }
281}
282
283#[derive(Clone, Debug)]
285pub struct InherentImpl {
286 pub(crate) register_methods_constants_fn: ErasedRegisterFn,
290
291 #[cfg_attr(not(feature = "codegen-full"), expect(dead_code))]
298 pub(crate) register_rpcs_fn: Option<ErasedRegisterRpcsFn>,
299
300 #[cfg(all(since_api = "4.3", feature = "register-docs"))] #[cfg_attr(published_docs, doc(cfg(all(since_api = "4.3", feature = "register-docs"))))]
301 pub docs: InherentImplDocs,
302}
303
304impl InherentImpl {
305 pub fn new<T: cap::ImplementsGodotApi>(
306 #[cfg(all(since_api = "4.3", feature = "register-docs"))] #[cfg_attr(published_docs, doc(cfg(all(since_api = "4.3", feature = "register-docs"))))] docs: InherentImplDocs,
307 ) -> Self {
308 Self {
309 register_methods_constants_fn: ErasedRegisterFn {
310 raw: callbacks::register_user_methods_constants::<T>,
311 },
312 register_rpcs_fn: Some(ErasedRegisterRpcsFn {
313 raw: callbacks::register_user_rpcs::<T>,
314 }),
315 #[cfg(all(since_api = "4.3", feature = "register-docs"))] #[cfg_attr(published_docs, doc(cfg(all(since_api = "4.3", feature = "register-docs"))))]
316 docs,
317 }
318 }
319}
320
321#[derive(Default, Clone, Debug)]
322pub struct ITraitImpl {
323 #[cfg(all(since_api = "4.3", feature = "register-docs"))]
324 pub(crate) virtual_method_docs: &'static str,
326
327 pub(crate) user_register_fn: Option<ErasedRegisterFn>,
329
330 pub(crate) user_create_fn: Option<GodotCreateFn>,
334
335 pub(crate) user_recreate_fn: Option<
339 unsafe extern "C" fn(
340 p_class_userdata: *mut ::std::os::raw::c_void,
341 p_object: sys::GDExtensionObjectPtr,
342 ) -> sys::GDExtensionClassInstancePtr,
343 >,
344
345 pub(crate) user_to_string_fn: Option<
347 unsafe extern "C" fn(
348 p_instance: sys::GDExtensionClassInstancePtr,
349 r_is_valid: *mut sys::GDExtensionBool,
350 r_out: sys::GDExtensionStringPtr,
351 ),
352 >,
353
354 #[cfg(before_api = "4.2")] #[cfg_attr(published_docs, doc(cfg(before_api = "4.2")))]
356 pub(crate) user_on_notification_fn:
357 Option<unsafe extern "C" fn(p_instance: sys::GDExtensionClassInstancePtr, p_what: i32)>,
358 #[cfg(since_api = "4.2")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.2")))]
359 pub(crate) user_on_notification_fn: Option<
360 unsafe extern "C" fn(
361 p_instance: sys::GDExtensionClassInstancePtr,
362 p_what: i32,
363 p_reversed: sys::GDExtensionBool,
364 ),
365 >,
366
367 pub(crate) user_set_fn: Option<
369 unsafe extern "C" fn(
370 p_instance: sys::GDExtensionClassInstancePtr,
371 p_name: sys::GDExtensionConstStringNamePtr,
372 p_value: sys::GDExtensionConstVariantPtr,
373 ) -> sys::GDExtensionBool,
374 >,
375
376 pub(crate) user_get_fn: Option<
378 unsafe extern "C" fn(
379 p_instance: sys::GDExtensionClassInstancePtr,
380 p_name: sys::GDExtensionConstStringNamePtr,
381 r_ret: sys::GDExtensionVariantPtr,
382 ) -> sys::GDExtensionBool,
383 >,
384
385 pub(crate) get_virtual_fn: Option<GodotGetVirtual>,
387
388 pub(crate) user_get_property_list_fn: Option<
390 unsafe extern "C" fn(
391 p_instance: sys::GDExtensionClassInstancePtr,
392 r_count: *mut u32,
393 ) -> *const sys::GDExtensionPropertyInfo,
394 >,
395
396 #[cfg(before_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(before_api = "4.3")))]
399 pub(crate) user_free_property_list_fn: Option<
400 unsafe extern "C" fn(
401 p_instance: sys::GDExtensionClassInstancePtr,
402 p_list: *const sys::GDExtensionPropertyInfo,
403 ),
404 >,
405 #[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
407 pub(crate) user_free_property_list_fn: Option<
408 unsafe extern "C" fn(
409 p_instance: sys::GDExtensionClassInstancePtr,
410 p_list: *const sys::GDExtensionPropertyInfo,
411 p_count: u32,
412 ),
413 >,
414
415 pub(crate) user_property_can_revert_fn: Option<
419 unsafe extern "C" fn(
420 p_instance: sys::GDExtensionClassInstancePtr,
421 p_name: sys::GDExtensionConstStringNamePtr,
422 ) -> sys::GDExtensionBool,
423 >,
424
425 pub(crate) user_property_get_revert_fn: Option<
430 unsafe extern "C" fn(
431 p_instance: sys::GDExtensionClassInstancePtr,
432 p_name: sys::GDExtensionConstStringNamePtr,
433 r_ret: sys::GDExtensionVariantPtr,
434 ) -> sys::GDExtensionBool,
435 >,
436 #[cfg(since_api = "4.2")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.2")))]
437 pub(crate) validate_property_fn: Option<
438 unsafe extern "C" fn(
439 p_instance: sys::GDExtensionClassInstancePtr,
440 p_property: *mut sys::GDExtensionPropertyInfo,
441 ) -> sys::GDExtensionBool,
442 >,
443}
444
445impl ITraitImpl {
446 pub fn new<T: GodotClass + cap::ImplementsGodotVirtual>(
447 #[cfg(all(since_api = "4.3", feature = "register-docs"))] #[cfg_attr(published_docs, doc(cfg(all(since_api = "4.3", feature = "register-docs"))))] virtual_method_docs: &'static str,
448 ) -> Self {
449 Self {
450 #[cfg(all(since_api = "4.3", feature = "register-docs"))] #[cfg_attr(published_docs, doc(cfg(all(since_api = "4.3", feature = "register-docs"))))]
451 virtual_method_docs,
452 get_virtual_fn: Some(callbacks::get_virtual::<T>),
453 ..Default::default()
454 }
455 }
456
457 pub fn with_register<T: GodotClass + cap::GodotRegisterClass>(mut self) -> Self {
458 set(
459 &mut self.user_register_fn,
460 ErasedRegisterFn {
461 raw: callbacks::register_class_by_builder::<T>,
462 },
463 );
464
465 self
466 }
467
468 pub fn with_create<T: GodotClass + cap::GodotDefault>(mut self) -> Self {
469 set(&mut self.user_create_fn, callbacks::create::<T>);
470
471 #[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
472 set(&mut self.user_recreate_fn, callbacks::recreate::<T>);
473 self
474 }
475
476 pub fn with_string<T: GodotClass + cap::GodotToString>(mut self) -> Self {
477 set(&mut self.user_to_string_fn, callbacks::to_string::<T>);
478 self
479 }
480
481 pub fn with_on_notification<T: GodotClass + cap::GodotNotification>(mut self) -> Self {
482 set(
483 &mut self.user_on_notification_fn,
484 callbacks::on_notification::<T>,
485 );
486 self
487 }
488
489 pub fn with_get_property<T: GodotClass + cap::GodotGet>(mut self) -> Self {
490 set(&mut self.user_get_fn, callbacks::get_property::<T>);
491 self
492 }
493
494 pub fn with_set_property<T: GodotClass + cap::GodotSet>(mut self) -> Self {
495 set(&mut self.user_set_fn, callbacks::set_property::<T>);
496 self
497 }
498
499 pub fn with_get_property_list<T: GodotClass + cap::GodotGetPropertyList>(mut self) -> Self {
500 set(
501 &mut self.user_get_property_list_fn,
502 callbacks::get_property_list::<T>,
503 );
504
505 #[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
506 set(
507 &mut self.user_free_property_list_fn,
508 callbacks::free_property_list::<T>,
509 );
510 self
511 }
512
513 pub fn with_property_get_revert<T: GodotClass + cap::GodotPropertyGetRevert>(mut self) -> Self {
514 set(
515 &mut self.user_property_get_revert_fn,
516 callbacks::property_get_revert::<T>,
517 );
518 set(
519 &mut self.user_property_can_revert_fn,
520 callbacks::property_can_revert::<T>,
521 );
522 self
523 }
524
525 #[cfg(since_api = "4.2")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.2")))]
526 pub fn with_validate_property<T: GodotClass + cap::GodotValidateProperty>(mut self) -> Self {
527 set(
528 &mut self.validate_property_fn,
529 callbacks::validate_property::<T>,
530 );
531 self
532 }
533}
534
535#[derive(Clone, Debug)]
539pub struct DynTraitImpl {
540 class_name: ClassName,
542
543 pub(crate) parent_class_name: Option<ClassName>,
552
553 dyn_trait_typeid: any::TypeId,
555
556 erased_dynify_fn: ErasedDynifyFn,
562}
563
564impl DynTraitImpl {
565 pub fn new<T, D>() -> Self
566 where
567 T: GodotClass
568 + Inherits<classes::Object>
569 + crate::obj::AsDyn<D>
570 + Bounds<Declarer = bounds::DeclUser>,
571 D: ?Sized + 'static,
572 {
573 Self {
574 class_name: T::class_name(),
575 parent_class_name: None,
576 dyn_trait_typeid: std::any::TypeId::of::<D>(),
577 erased_dynify_fn: callbacks::dynify_fn::<T, D>,
578 }
579 }
580
581 pub fn class_name(&self) -> &ClassName {
583 &self.class_name
584 }
585
586 pub fn dyn_trait_typeid(&self) -> any::TypeId {
588 self.dyn_trait_typeid
589 }
590
591 pub fn get_dyn_gd<T: GodotClass, D: ?Sized + 'static>(
595 &self,
596 object: Gd<T>,
597 ) -> Result<DynGd<T, D>, Gd<T>> {
598 let dynamic_class = object.dynamic_class_string();
599
600 if dynamic_class != self.class_name.to_string_name() {
601 return Err(object);
602 }
603
604 let object = object.upcast_object();
605
606 let erased_dyn = unsafe { (self.erased_dynify_fn)(object) };
609
610 let dyn_gd_object = erased_dyn.boxed.downcast::<DynGd<classes::Object, D>>();
611
612 let dyn_gd_object = unsafe { dyn_gd_object.unwrap_unchecked() };
614
615 let dyn_gd_t = unsafe { dyn_gd_object.cast_unchecked::<T>() };
619
620 Ok(dyn_gd_t)
621 }
622}