1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
use crate::addons::module::Module;
use crate::prelude::*;
use crate::sys;
/// Module mixin implementation
impl World {
/// Import a module.
///
/// This operation will load a module. The module name will be used to verify if
/// the module was already loaded, in which case it won't be reimported.
///
/// Module contents will be stored as children of the module entity. This
/// prevents modules from accidentally defining conflicting identifiers. This is
/// enforced by setting the scope before and after loading the module to the
/// module entity id.
///
/// ```
/// # use flecs_ecs::prelude::*;
/// # #[derive(Component)]
/// # struct MyModule;
/// # impl Module for MyModule {
/// # fn module(_world: &World) {
/// # }
/// # }
/// # let world = World::new();
/// world.import::<MyModule>();
/// ```
///
/// # See also
///
/// * [`addons::module`](crate::addons::module)
/// * [`Module`]
/// * [`World::module()`]
pub fn import<T: Module>(&self) -> EntityView<'_> {
// Reset scope
let prev_scope = self.set_scope(0);
let world = self.world();
let raw_world = self.raw_world.as_ptr();
let symbol_name = core::any::type_name::<T>();
let symbol = compact_str::format_compact!("{}\0", symbol_name);
let m =
unsafe { sys::ecs_lookup_symbol(raw_world, symbol.as_ptr() as *const i8, true, false) };
let module = if T::is_registered_with_world(self) && m != 0 {
self.component::<T>().entity
} else {
let id = self.entity_from_id(register_component_data_explicit::<T, true>(
world,
core::ptr::null(),
));
let id_u64 = *id.id();
let index = T::index() as usize;
let components_array = self.components_array();
components_array[index] = id_u64;
#[cfg(feature = "flecs_meta")]
{
self.components_map()
.insert(core::any::TypeId::of::<Self>(), id_u64);
}
id
};
// If we have already registered this type don't re-create the module
if module.has(id::<flecs::Module>()) {
return module;
}
// Make module component sparse so that it'll never move in memory. This
// guarantees that a module drop / destructor can be reliably used to cleanup
// module resources.
module.add_trait::<flecs::Sparse>();
module.add_trait::<flecs::Singleton>();
// Set scope to our module
self.set_scope(module);
let module_id = *module.id();
unsafe { sys::ecs_add_id(raw_world, module_id, module_id) };
unsafe { sys::ecs_modified_id(raw_world, module_id, module_id) };
// Build the module
T::module(self);
// Return out scope to the previous scope
self.set_scope(prev_scope);
// Initialise component for the module and add Module tag
unsafe { module.add_id_unchecked(flecs::Module::ID) };
module
}
/// Define a module.
///
/// This operation is not mandatory, but can be called inside the module ctor to
/// obtain the entity associated with the module, or override the module name.
///
/// # Type Parameters
///
/// * `M` - The type of the module.
///
/// # Arguments
///
/// * `name` - The name to give the module.
///
/// # Returns
///
/// The module entity.
///
/// # See also
///
/// * [`addons::module`](crate::addons::module)
/// * [`Module`]
/// * [`World::import()`]
pub fn module<M: ComponentId>(&self, name: &str) -> EntityView<'_> {
let comp = self.component::<M>();
let id = comp.id();
if let Some(existing) = self.try_lookup_recursive(name) {
self.set_scope(existing);
return existing;
}
if !name.is_empty() {
let name = compact_str::format_compact!("{}\0", name);
let prev_parent = comp.parent().unwrap_or(EntityView::new_null(self));
unsafe {
sys::ecs_add_path_w_sep(
self.raw_world.as_ptr(),
*id,
0,
name.as_ptr() as *const _,
SEPARATOR.as_ptr(),
SEPARATOR.as_ptr(),
);
}
let parent = comp.parent().unwrap_or(EntityView::new_null(self));
if parent != prev_parent {
// Module was reparented, cleanup old parent(s)
let mut cur = prev_parent;
let mut next;
while cur.id != 0 {
next = cur.parent().unwrap_or(EntityView::new_null(self));
let mut it = unsafe {
sys::ecs_each_id(
self.world_ptr(),
ecs_pair(flecs::ChildOf::ID, cur.id.into()),
)
};
if !unsafe { sys::ecs_iter_is_true(&mut it) } {
cur.destruct();
// Prevent increasing the generation count of the temporary
// parent. This allows entities created during
// initialization to keep non-recycled ids.
self.set_version(cur);
}
cur = next;
if cur.id == 0 {
break;
}
}
}
}
EntityView::new_from(self, *id)
}
}