1use std::{
4 any::type_name,
5 mem::MaybeUninit,
6 ops::Index,
7 panic::{AssertUnwindSafe, catch_unwind, resume_unwind},
8};
9
10use bevy_ecs::{
11 component::{ComponentId, ComponentIdFor},
12 prelude::*,
13 query::{QueryItem, ReadOnlyQueryData},
14 storage::SparseSet,
15 system::{
16 ReadOnlySystemParam, SystemParamItem, SystemState,
17 lifetimeless::{Read, SQuery},
18 },
19 world::unsafe_world_cell::UnsafeWorldCell,
20};
21use bevy_math::prelude::*;
22
23pub trait Measure: Component {
32 type Param: ReadOnlySystemParam;
34 type Item: ReadOnlyQueryData;
37
38 fn measure(
40 &self,
41 param: &SystemParamItem<Self::Param>,
42 item: QueryItem<Self::Item>,
43 known_size: (Option<f32>, Option<f32>),
44 available_space: (AvailableSpace, AvailableSpace),
45 ) -> Vec2;
46}
47
48pub(crate) fn on_measure_inserted<T: Measure>(
49 trigger: Trigger<OnInsert, T>,
50 mut commands: Commands,
51 measurements: Res<Measurements>,
52 id: ComponentIdFor<T>,
53) {
54 let e = trigger.entity();
55 commands.entity(e).insert(ContentSize(
56 measurements
57 .get(id.get())
58 .unwrap_or_else(|| panic!("`{}` not registered", type_name::<T>())),
59 ));
60}
61
62#[derive(Component, Copy, Clone)]
65pub struct ContentSize(MeasureId);
66impl ContentSize {
67 #[inline]
69 pub const fn get(self) -> MeasureId {
70 self.0
71 }
72}
73
74impl Default for ContentSize {
75 #[inline]
76 fn default() -> Self {
77 Self(MeasureId::INVALID)
78 }
79}
80
81#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
83pub struct MeasureId(usize);
84impl MeasureId {
85 pub const INVALID: Self = Self(usize::MAX);
87}
88
89#[derive(Copy, Clone, PartialEq, PartialOrd)]
91pub enum AvailableSpace {
92 Definite(f32),
94 MinContent,
97 MaxContent,
100}
101
102impl From<taffy::AvailableSpace> for AvailableSpace {
103 #[inline]
104 fn from(value: taffy::AvailableSpace) -> Self {
105 match value {
106 taffy::AvailableSpace::Definite(value) => Self::Definite(value),
107 taffy::AvailableSpace::MinContent => Self::MinContent,
108 taffy::AvailableSpace::MaxContent => Self::MaxContent,
109 }
110 }
111}
112
113#[derive(Resource, Default)]
115pub struct Measurements {
116 ids: SparseSet<ComponentId, MeasureId>,
117 data: Vec<Box<dyn MeasureDyn>>,
118}
119
120impl Measurements {
121 #[inline]
123 pub fn register<T: Measure>(&mut self, world: &mut World) -> MeasureId {
124 *self.ids.get_or_insert_with(world.register_component::<T>(), || {
125 self.data.push(Box::new(MeasureImpl::<T> {
126 state: SystemState::new(world),
127 fetch: MaybeUninit::uninit(),
128 }));
129
130 MeasureId(self.data.len() - 1)
131 })
132 }
133
134 #[inline]
136 pub fn get(&self, id: ComponentId) -> Option<MeasureId> {
137 self.ids.get(id).copied()
138 }
139
140 #[inline]
149 pub unsafe fn get_measurers(&mut self, world: UnsafeWorldCell) -> impl Index<MeasureId, Output = dyn Measurer> {
150 struct Guard<'a> {
151 measurers: &'a mut [Box<dyn MeasureDyn>],
152 }
153
154 impl Index<MeasureId> for Guard<'_> {
155 type Output = dyn Measurer;
156
157 #[inline]
158 fn index(&self, index: MeasureId) -> &Self::Output {
159 unsafe { self.measurers[index.0].as_measurer() }
161 }
162 }
163
164 impl Drop for Guard<'_> {
165 fn drop(&mut self) {
166 for measurer in &mut *self.measurers {
167 unsafe { measurer.finish_fetch() }
168 }
169 }
170 }
171
172 for (i, data) in self.data.iter_mut().enumerate() {
173 if let Err(e) = catch_unwind(AssertUnwindSafe(|| unsafe { data.init_fetch(world) })) {
174 for i in 0..i {
175 unsafe { self.data[i].finish_fetch() }
176 }
177
178 resume_unwind(e)
179 }
180 }
181
182 Guard {
183 measurers: &mut self.data,
184 }
185 }
186
187 pub fn apply_measurers(&mut self, world: &mut World) {
189 for data in &mut self.data {
190 data.apply(world)
191 }
192 }
193}
194
195pub trait Measurer: 'static + Send + Sync {
197 fn measure(
199 &self,
200 known_size: (Option<f32>, Option<f32>),
201 available_space: (AvailableSpace, AvailableSpace),
202 entity: Entity,
203 ) -> Vec2;
204}
205
206unsafe trait MeasureDyn: Measurer {
211 unsafe fn init_fetch<'w>(&'w mut self, world: UnsafeWorldCell<'w>);
212
213 unsafe fn finish_fetch(&mut self);
214
215 unsafe fn as_measurer(&self) -> &dyn Measurer;
216
217 fn apply(&mut self, world: &mut World);
218}
219
220impl<T: Measure> Measurer for MeasureImpl<T> {
221 #[inline]
222 fn measure<'w>(
223 &'w self,
224 known_size: (Option<f32>, Option<f32>),
225 available_space: (AvailableSpace, AvailableSpace),
226 entity: Entity,
227 ) -> Vec2 {
228 let (param, queue) = unsafe {
229 std::mem::transmute::<
230 &'w SystemParamItem<'static, 'static, (T::Param, SQuery<(Read<T>, T::Item)>)>,
231 &'w SystemParamItem<'w, 'w, (T::Param, SQuery<(Read<T>, T::Item)>)>,
232 >(self.fetch.assume_init_ref())
233 };
234
235 let Ok((measure, item)) = queue.get(entity) else {
236 return Vec2::ZERO;
237 };
238
239 measure.measure(param, item, known_size, available_space)
240 }
241}
242
243unsafe impl<T: Measure> MeasureDyn for MeasureImpl<T> {
244 #[inline]
245 unsafe fn init_fetch<'w>(&'w mut self, world: UnsafeWorldCell<'w>) {
246 self.state.update_archetypes_unsafe_world_cell(world);
247 unsafe {
248 self.fetch.as_mut_ptr().write(std::mem::transmute::<
249 SystemParamItem<'w, 'w, (T::Param, SQuery<(Read<T>, T::Item)>)>,
250 SystemParamItem<'static, 'static, (T::Param, SQuery<(Read<T>, T::Item)>)>,
251 >(self.state.get_unchecked_manual(world)))
252 }
253 }
254
255 #[inline]
256 unsafe fn finish_fetch(&mut self) {
257 unsafe { self.fetch.assume_init_drop() }
258 }
259
260 #[inline]
261 unsafe fn as_measurer(&self) -> &dyn Measurer {
262 self as &dyn Measurer
263 }
264
265 #[inline]
266 fn apply(&mut self, world: &mut World) {
267 self.state.apply(world)
268 }
269}
270
271struct MeasureImpl<T: Measure> {
272 state: SystemState<(T::Param, SQuery<(Read<T>, T::Item)>)>,
273 fetch: MaybeUninit<SystemParamItem<'static, 'static, (T::Param, SQuery<(Read<T>, T::Item)>)>>,
274}
275
276unsafe impl<T: Measure> Send for MeasureImpl<T> {}
277unsafe impl<T: Measure> Sync for MeasureImpl<T> {}