Thanks to visit codestin.com
Credit goes to docs.rs

bevy_ecs/storage/table/
column.rs

1use super::*;
2use crate::{
3    change_detection::MaybeLocation,
4    component::TickCells,
5    storage::{blob_array::BlobArray, thin_array_ptr::ThinArrayPtr},
6};
7use alloc::vec::Vec;
8use bevy_ptr::PtrMut;
9use core::panic::Location;
10
11/// Very similar to a normal [`Column`], but with the capacities and lengths cut out for performance reasons.
12///
13/// This type is used by [`Table`], because all of the capacities and lengths of the [`Table`]'s columns must match.
14///
15/// Like many other low-level storage types, [`ThinColumn`] has a limited and highly unsafe
16/// interface. It's highly advised to use higher level types and their safe abstractions
17/// instead of working directly with [`ThinColumn`].
18pub struct ThinColumn {
19    pub(super) data: BlobArray,
20    pub(super) added_ticks: ThinArrayPtr<UnsafeCell<Tick>>,
21    pub(super) changed_ticks: ThinArrayPtr<UnsafeCell<Tick>>,
22    pub(super) changed_by: MaybeLocation<ThinArrayPtr<UnsafeCell<&'static Location<'static>>>>,
23}
24
25impl ThinColumn {
26    /// Create a new [`ThinColumn`] with the given `capacity`.
27    pub fn with_capacity(component_info: &ComponentInfo, capacity: usize) -> Self {
28        Self {
29            // SAFETY: The components stored in this columns will match the information in `component_info`
30            data: unsafe {
31                BlobArray::with_capacity(component_info.layout(), component_info.drop(), capacity)
32            },
33            added_ticks: ThinArrayPtr::with_capacity(capacity),
34            changed_ticks: ThinArrayPtr::with_capacity(capacity),
35            changed_by: MaybeLocation::new_with(|| ThinArrayPtr::with_capacity(capacity)),
36        }
37    }
38
39    /// Swap-remove and drop the removed element, but the component at `row` must not be the last element.
40    ///
41    /// # Safety
42    /// - `row.as_usize()` < `len`
43    /// - `last_element_index` = `len - 1`
44    /// - `last_element_index` != `row.as_usize()`
45    /// -   The caller should update the `len` to `len - 1`, or immediately initialize another element in the `last_element_index`
46    pub(crate) unsafe fn swap_remove_and_drop_unchecked_nonoverlapping(
47        &mut self,
48        last_element_index: usize,
49        row: TableRow,
50    ) {
51        self.data
52            .swap_remove_and_drop_unchecked_nonoverlapping(row.index(), last_element_index);
53        self.added_ticks
54            .swap_remove_unchecked_nonoverlapping(row.index(), last_element_index);
55        self.changed_ticks
56            .swap_remove_unchecked_nonoverlapping(row.index(), last_element_index);
57        self.changed_by.as_mut().map(|changed_by| {
58            changed_by.swap_remove_unchecked_nonoverlapping(row.index(), last_element_index);
59        });
60    }
61
62    /// Swap-remove and drop the removed element.
63    ///
64    /// # Safety
65    /// - `last_element_index` must be the index of the last element—stored in the highest place in memory.
66    /// - `row.as_usize()` <= `last_element_index`
67    /// -   The caller should update the their saved length to reflect the change (decrement it by 1).
68    pub(crate) unsafe fn swap_remove_and_drop_unchecked(
69        &mut self,
70        last_element_index: usize,
71        row: TableRow,
72    ) {
73        self.data
74            .swap_remove_and_drop_unchecked(row.index(), last_element_index);
75        self.added_ticks
76            .swap_remove_and_drop_unchecked(row.index(), last_element_index);
77        self.changed_ticks
78            .swap_remove_and_drop_unchecked(row.index(), last_element_index);
79        self.changed_by.as_mut().map(|changed_by| {
80            changed_by.swap_remove_and_drop_unchecked(row.index(), last_element_index);
81        });
82    }
83
84    /// Swap-remove and forget the removed element.
85    ///
86    /// # Safety
87    /// - `last_element_index` must be the index of the last element—stored in the highest place in memory.
88    /// - `row.as_usize()` <= `last_element_index`
89    /// -   The caller should update the their saved length to reflect the change (decrement it by 1).
90    pub(crate) unsafe fn swap_remove_and_forget_unchecked(
91        &mut self,
92        last_element_index: usize,
93        row: TableRow,
94    ) {
95        let _ = self
96            .data
97            .swap_remove_unchecked(row.index(), last_element_index);
98        self.added_ticks
99            .swap_remove_unchecked(row.index(), last_element_index);
100        self.changed_ticks
101            .swap_remove_unchecked(row.index(), last_element_index);
102        self.changed_by
103            .as_mut()
104            .map(|changed_by| changed_by.swap_remove_unchecked(row.index(), last_element_index));
105    }
106
107    /// Call [`realloc`](std::alloc::realloc) to expand / shrink the memory allocation for this [`ThinColumn`]
108    ///
109    /// # Safety
110    /// - `current_capacity` must be the current capacity of this column (the capacity of `self.data`, `self.added_ticks`, `self.changed_tick`)
111    /// -   The caller should make sure their saved `capacity` value is updated to `new_capacity` after this operation.
112    pub(crate) unsafe fn realloc(
113        &mut self,
114        current_capacity: NonZeroUsize,
115        new_capacity: NonZeroUsize,
116    ) {
117        self.data.realloc(current_capacity, new_capacity);
118        self.added_ticks.realloc(current_capacity, new_capacity);
119        self.changed_ticks.realloc(current_capacity, new_capacity);
120        self.changed_by
121            .as_mut()
122            .map(|changed_by| changed_by.realloc(current_capacity, new_capacity));
123    }
124
125    /// Call [`alloc`](std::alloc::alloc) to allocate memory for this [`ThinColumn`]
126    /// The caller should make sure their saved `capacity` value is updated to `new_capacity` after this operation.
127    pub(crate) fn alloc(&mut self, new_capacity: NonZeroUsize) {
128        self.data.alloc(new_capacity);
129        self.added_ticks.alloc(new_capacity);
130        self.changed_ticks.alloc(new_capacity);
131        self.changed_by
132            .as_mut()
133            .map(|changed_by| changed_by.alloc(new_capacity));
134    }
135
136    /// Writes component data to the column at the given row.
137    /// Assumes the slot is uninitialized, drop is not called.
138    /// To overwrite existing initialized value, use [`Self::replace`] instead.
139    ///
140    /// # Safety
141    /// - `row.as_usize()` must be in bounds.
142    /// - `comp_ptr` holds a component that matches the `component_id`
143    #[inline]
144    pub(crate) unsafe fn initialize(
145        &mut self,
146        row: TableRow,
147        data: OwningPtr<'_>,
148        tick: Tick,
149        caller: MaybeLocation,
150    ) {
151        self.data.initialize_unchecked(row.index(), data);
152        *self.added_ticks.get_unchecked_mut(row.index()).get_mut() = tick;
153        *self.changed_ticks.get_unchecked_mut(row.index()).get_mut() = tick;
154        self.changed_by
155            .as_mut()
156            .map(|changed_by| changed_by.get_unchecked_mut(row.index()).get_mut())
157            .assign(caller);
158    }
159
160    /// Writes component data to the column at given row. Assumes the slot is initialized, drops the previous value.
161    ///
162    /// # Safety
163    /// - `row.as_usize()` must be in bounds.
164    /// - `data` holds a component that matches the `component_id`
165    #[inline]
166    pub(crate) unsafe fn replace(
167        &mut self,
168        row: TableRow,
169        data: OwningPtr<'_>,
170        change_tick: Tick,
171        caller: MaybeLocation,
172    ) {
173        self.data.replace_unchecked(row.index(), data);
174        *self.changed_ticks.get_unchecked_mut(row.index()).get_mut() = change_tick;
175        self.changed_by
176            .as_mut()
177            .map(|changed_by| changed_by.get_unchecked_mut(row.index()).get_mut())
178            .assign(caller);
179    }
180
181    /// Removes the element from `other` at `src_row` and inserts it
182    /// into the current column to initialize the values at `dst_row`.
183    /// Does not do any bounds checking.
184    ///
185    /// # Safety
186    ///  - `other` must have the same data layout as `self`
187    ///  - `src_row` must be in bounds for `other`
188    ///  - `dst_row` must be in bounds for `self`
189    ///  - `other[src_row]` must be initialized to a valid value.
190    ///  - `self[dst_row]` must not be initialized yet.
191    #[inline]
192    pub(crate) unsafe fn initialize_from_unchecked(
193        &mut self,
194        other: &mut ThinColumn,
195        other_last_element_index: usize,
196        src_row: TableRow,
197        dst_row: TableRow,
198    ) {
199        debug_assert!(self.data.layout() == other.data.layout());
200        // Init the data
201        let src_val = other
202            .data
203            .swap_remove_unchecked(src_row.index(), other_last_element_index);
204        self.data.initialize_unchecked(dst_row.index(), src_val);
205        // Init added_ticks
206        let added_tick = other
207            .added_ticks
208            .swap_remove_unchecked(src_row.index(), other_last_element_index);
209        self.added_ticks
210            .initialize_unchecked(dst_row.index(), added_tick);
211        // Init changed_ticks
212        let changed_tick = other
213            .changed_ticks
214            .swap_remove_unchecked(src_row.index(), other_last_element_index);
215        self.changed_ticks
216            .initialize_unchecked(dst_row.index(), changed_tick);
217        self.changed_by.as_mut().zip(other.changed_by.as_mut()).map(
218            |(self_changed_by, other_changed_by)| {
219                let changed_by = other_changed_by
220                    .swap_remove_unchecked(src_row.index(), other_last_element_index);
221                self_changed_by.initialize_unchecked(dst_row.index(), changed_by);
222            },
223        );
224    }
225
226    /// Call [`Tick::check_tick`] on all of the ticks stored in this column.
227    ///
228    /// # Safety
229    /// `len` is the actual length of this column
230    #[inline]
231    pub(crate) unsafe fn check_change_ticks(&mut self, len: usize, check: CheckChangeTicks) {
232        for i in 0..len {
233            // SAFETY:
234            // - `i` < `len`
235            // we have a mutable reference to `self`
236            unsafe { self.added_ticks.get_unchecked_mut(i) }
237                .get_mut()
238                .check_tick(check);
239            // SAFETY:
240            // - `i` < `len`
241            // we have a mutable reference to `self`
242            unsafe { self.changed_ticks.get_unchecked_mut(i) }
243                .get_mut()
244                .check_tick(check);
245        }
246    }
247
248    /// Clear all the components from this column.
249    ///
250    /// # Safety
251    /// - `len` must match the actual length of the column
252    /// -   The caller must not use the elements this column's data until [`initializing`](Self::initialize) it again (set `len` to 0).
253    pub(crate) unsafe fn clear(&mut self, len: usize) {
254        self.added_ticks.clear_elements(len);
255        self.changed_ticks.clear_elements(len);
256        self.data.clear(len);
257        self.changed_by
258            .as_mut()
259            .map(|changed_by| changed_by.clear_elements(len));
260    }
261
262    /// Because this method needs parameters, it can't be the implementation of the `Drop` trait.
263    /// The owner of this [`ThinColumn`] must call this method with the correct information.
264    ///
265    /// # Safety
266    /// - `len` is indeed the length of the column
267    /// - `cap` is indeed the capacity of the column
268    /// - the data stored in `self` will never be used again
269    pub(crate) unsafe fn drop(&mut self, cap: usize, len: usize) {
270        self.added_ticks.drop(cap, len);
271        self.changed_ticks.drop(cap, len);
272        self.data.drop(cap, len);
273        self.changed_by
274            .as_mut()
275            .map(|changed_by| changed_by.drop(cap, len));
276    }
277
278    /// Drops the last component in this column.
279    ///
280    /// # Safety
281    /// - `last_element_index` is indeed the index of the last element
282    /// - the data stored in `last_element_index` will never be used unless properly initialized again.
283    pub(crate) unsafe fn drop_last_component(&mut self, last_element_index: usize) {
284        core::ptr::drop_in_place(self.added_ticks.get_unchecked_raw(last_element_index));
285        core::ptr::drop_in_place(self.changed_ticks.get_unchecked_raw(last_element_index));
286        self.changed_by.as_mut().map(|changed_by| {
287            core::ptr::drop_in_place(changed_by.get_unchecked_raw(last_element_index));
288        });
289        self.data.drop_last_element(last_element_index);
290    }
291
292    /// Get a slice to the data stored in this [`ThinColumn`].
293    ///
294    /// # Safety
295    /// - `T` must match the type of data that's stored in this [`ThinColumn`]
296    /// - `len` must match the actual length of this column (number of elements stored)
297    pub unsafe fn get_data_slice<T>(&self, len: usize) -> &[UnsafeCell<T>] {
298        self.data.get_sub_slice(len)
299    }
300
301    /// Get a slice to the added [`ticks`](Tick) in this [`ThinColumn`].
302    ///
303    /// # Safety
304    /// - `len` must match the actual length of this column (number of elements stored)
305    pub unsafe fn get_added_ticks_slice(&self, len: usize) -> &[UnsafeCell<Tick>] {
306        self.added_ticks.as_slice(len)
307    }
308
309    /// Get a slice to the changed [`ticks`](Tick) in this [`ThinColumn`].
310    ///
311    /// # Safety
312    /// - `len` must match the actual length of this column (number of elements stored)
313    pub unsafe fn get_changed_ticks_slice(&self, len: usize) -> &[UnsafeCell<Tick>] {
314        self.changed_ticks.as_slice(len)
315    }
316
317    /// Get a slice to the calling locations that last changed each value in this [`ThinColumn`]
318    ///
319    /// # Safety
320    /// - `len` must match the actual length of this column (number of elements stored)
321    pub unsafe fn get_changed_by_slice(
322        &self,
323        len: usize,
324    ) -> MaybeLocation<&[UnsafeCell<&'static Location<'static>>]> {
325        self.changed_by
326            .as_ref()
327            .map(|changed_by| changed_by.as_slice(len))
328    }
329}
330
331/// A type-erased contiguous container for data of a homogeneous type.
332///
333/// Conceptually, a [`Column`] is very similar to a type-erased `Vec<T>`.
334/// It also stores the change detection ticks for its components, kept in two separate
335/// contiguous buffers internally. An element shares its data across these buffers by using the
336/// same index (i.e. the entity at row 3 has it's data at index 3 and its change detection ticks at index 3).
337///
338/// Like many other low-level storage types, [`Column`] has a limited and highly unsafe
339/// interface. It's highly advised to use higher level types and their safe abstractions
340/// instead of working directly with [`Column`].
341#[derive(Debug)]
342pub struct Column {
343    pub(super) data: BlobVec,
344    pub(super) added_ticks: Vec<UnsafeCell<Tick>>,
345    pub(super) changed_ticks: Vec<UnsafeCell<Tick>>,
346    changed_by: MaybeLocation<Vec<UnsafeCell<&'static Location<'static>>>>,
347}
348
349impl Column {
350    /// Constructs a new [`Column`], configured with a component's layout and an initial `capacity`.
351    #[inline]
352    pub(crate) fn with_capacity(component_info: &ComponentInfo, capacity: usize) -> Self {
353        Column {
354            // SAFETY: component_info.drop() is valid for the types that will be inserted.
355            data: unsafe { BlobVec::new(component_info.layout(), component_info.drop(), capacity) },
356            added_ticks: Vec::with_capacity(capacity),
357            changed_ticks: Vec::with_capacity(capacity),
358            changed_by: MaybeLocation::new_with(|| Vec::with_capacity(capacity)),
359        }
360    }
361
362    /// Fetches the [`Layout`] for the underlying type.
363    #[inline]
364    pub fn item_layout(&self) -> Layout {
365        self.data.layout()
366    }
367
368    /// Writes component data to the column at given row.
369    /// Assumes the slot is initialized, calls drop.
370    ///
371    /// # Safety
372    /// Assumes data has already been allocated for the given row.
373    #[inline]
374    pub(crate) unsafe fn replace(
375        &mut self,
376        row: TableRow,
377        data: OwningPtr<'_>,
378        change_tick: Tick,
379        caller: MaybeLocation,
380    ) {
381        debug_assert!(row.index() < self.len());
382        self.data.replace_unchecked(row.index(), data);
383        *self.changed_ticks.get_unchecked_mut(row.index()).get_mut() = change_tick;
384        self.changed_by
385            .as_mut()
386            .map(|changed_by| changed_by.get_unchecked_mut(row.index()).get_mut())
387            .assign(caller);
388    }
389
390    /// Gets the current number of elements stored in the column.
391    #[inline]
392    pub fn len(&self) -> usize {
393        self.data.len()
394    }
395
396    /// Checks if the column is empty. Returns `true` if there are no elements, `false` otherwise.
397    #[inline]
398    pub fn is_empty(&self) -> bool {
399        self.data.is_empty()
400    }
401
402    /// Removes an element from the [`Column`].
403    ///
404    /// - The value will be dropped if it implements [`Drop`].
405    /// - This does not preserve ordering, but is O(1).
406    /// - This does not do any bounds checking.
407    /// - The element is replaced with the last element in the [`Column`].
408    ///
409    /// # Safety
410    /// `row` must be within the range `[0, self.len())`.
411    #[inline]
412    pub(crate) unsafe fn swap_remove_unchecked(&mut self, row: TableRow) {
413        self.data.swap_remove_and_drop_unchecked(row.index());
414        self.added_ticks.swap_remove(row.index());
415        self.changed_ticks.swap_remove(row.index());
416        self.changed_by
417            .as_mut()
418            .map(|changed_by| changed_by.swap_remove(row.index()));
419    }
420
421    /// Removes an element from the [`Column`] and returns it and its change detection ticks.
422    /// This does not preserve ordering, but is O(1) and does not do any bounds checking.
423    ///
424    /// The element is replaced with the last element in the [`Column`].
425    ///
426    /// It's the caller's responsibility to ensure that the removed value is dropped or used.
427    /// Failure to do so may result in resources not being released (i.e. files handles not being
428    /// released, memory leaks, etc.)
429    ///
430    /// # Safety
431    /// `row` must be within the range `[0, self.len())`.
432    #[inline]
433    #[must_use = "The returned pointer should be used to dropped the removed component"]
434    pub(crate) unsafe fn swap_remove_and_forget_unchecked(
435        &mut self,
436        row: TableRow,
437    ) -> (OwningPtr<'_>, ComponentTicks, MaybeLocation) {
438        let data = self.data.swap_remove_and_forget_unchecked(row.index());
439        let added = self.added_ticks.swap_remove(row.index()).into_inner();
440        let changed = self.changed_ticks.swap_remove(row.index()).into_inner();
441        let caller = self
442            .changed_by
443            .as_mut()
444            .map(|changed_by| changed_by.swap_remove(row.index()).into_inner());
445        (data, ComponentTicks { added, changed }, caller)
446    }
447
448    /// Pushes a new value onto the end of the [`Column`].
449    ///
450    /// # Safety
451    /// `ptr` must point to valid data of this column's component type
452    pub(crate) unsafe fn push(
453        &mut self,
454        ptr: OwningPtr<'_>,
455        ticks: ComponentTicks,
456        caller: MaybeLocation,
457    ) {
458        self.data.push(ptr);
459        self.added_ticks.push(UnsafeCell::new(ticks.added));
460        self.changed_ticks.push(UnsafeCell::new(ticks.changed));
461        self.changed_by
462            .as_mut()
463            .zip(caller)
464            .map(|(changed_by, caller)| changed_by.push(UnsafeCell::new(caller)));
465    }
466
467    /// Fetches the data pointer to the first element of the [`Column`].
468    ///
469    /// The pointer is type erased, so using this function to fetch anything
470    /// other than the first element will require computing the offset using
471    /// [`Column::item_layout`].
472    #[inline]
473    pub fn get_data_ptr(&self) -> Ptr<'_> {
474        self.data.get_ptr()
475    }
476
477    /// Fetches the slice to the [`Column`]'s data cast to a given type.
478    ///
479    /// Note: The values stored within are [`UnsafeCell`].
480    /// Users of this API must ensure that accesses to each individual element
481    /// adhere to the safety invariants of [`UnsafeCell`].
482    ///
483    /// # Safety
484    /// The type `T` must be the type of the items in this column.
485    pub unsafe fn get_data_slice<T>(&self) -> &[UnsafeCell<T>] {
486        self.data.get_slice()
487    }
488
489    /// Fetches the slice to the [`Column`]'s "added" change detection ticks.
490    ///
491    /// Note: The values stored within are [`UnsafeCell`].
492    /// Users of this API must ensure that accesses to each individual element
493    /// adhere to the safety invariants of [`UnsafeCell`].
494    #[inline]
495    pub fn get_added_ticks_slice(&self) -> &[UnsafeCell<Tick>] {
496        &self.added_ticks
497    }
498
499    /// Fetches the slice to the [`Column`]'s "changed" change detection ticks.
500    ///
501    /// Note: The values stored within are [`UnsafeCell`].
502    /// Users of this API must ensure that accesses to each individual element
503    /// adhere to the safety invariants of [`UnsafeCell`].
504    #[inline]
505    pub fn get_changed_ticks_slice(&self) -> &[UnsafeCell<Tick>] {
506        &self.changed_ticks
507    }
508
509    /// Fetches a reference to the data and change detection ticks at `row`.
510    ///
511    /// Returns `None` if `row` is out of bounds.
512    #[inline]
513    pub fn get(&self, row: TableRow) -> Option<(Ptr<'_>, TickCells<'_>)> {
514        (row.index() < self.data.len())
515            // SAFETY: The row is length checked before fetching the pointer. This is being
516            // accessed through a read-only reference to the column.
517            .then(|| unsafe {
518                (
519                    self.data.get_unchecked(row.index()),
520                    TickCells {
521                        added: self.added_ticks.get_unchecked(row.index()),
522                        changed: self.changed_ticks.get_unchecked(row.index()),
523                    },
524                )
525            })
526    }
527
528    /// Fetches a read-only reference to the data at `row`.
529    ///
530    /// Returns `None` if `row` is out of bounds.
531    #[inline]
532    pub fn get_data(&self, row: TableRow) -> Option<Ptr<'_>> {
533        (row.index() < self.data.len()).then(|| {
534            // SAFETY: The row is length checked before fetching the pointer. This is being
535            // accessed through a read-only reference to the column.
536            unsafe { self.data.get_unchecked(row.index()) }
537        })
538    }
539
540    /// Fetches a read-only reference to the data at `row`. Unlike [`Column::get`] this does not
541    /// do any bounds checking.
542    ///
543    /// # Safety
544    /// - `row` must be within the range `[0, self.len())`.
545    /// - no other mutable reference to the data of the same row can exist at the same time
546    #[inline]
547    pub unsafe fn get_data_unchecked(&self, row: TableRow) -> Ptr<'_> {
548        debug_assert!(row.index() < self.data.len());
549        self.data.get_unchecked(row.index())
550    }
551
552    /// Fetches a mutable reference to the data at `row`.
553    ///
554    /// Returns `None` if `row` is out of bounds.
555    #[inline]
556    pub fn get_data_mut(&mut self, row: TableRow) -> Option<PtrMut<'_>> {
557        (row.index() < self.data.len()).then(|| {
558            // SAFETY: The row is length checked before fetching the pointer. This is being
559            // accessed through an exclusive reference to the column.
560            unsafe { self.data.get_unchecked_mut(row.index()) }
561        })
562    }
563
564    /// Fetches the "added" change detection tick for the value at `row`.
565    ///
566    /// Returns `None` if `row` is out of bounds.
567    ///
568    /// Note: The values stored within are [`UnsafeCell`].
569    /// Users of this API must ensure that accesses to each individual element
570    /// adhere to the safety invariants of [`UnsafeCell`].
571    #[inline]
572    pub fn get_added_tick(&self, row: TableRow) -> Option<&UnsafeCell<Tick>> {
573        self.added_ticks.get(row.index())
574    }
575
576    /// Fetches the "changed" change detection tick for the value at `row`.
577    ///
578    /// Returns `None` if `row` is out of bounds.
579    ///
580    /// Note: The values stored within are [`UnsafeCell`].
581    /// Users of this API must ensure that accesses to each individual element
582    /// adhere to the safety invariants of [`UnsafeCell`].
583    #[inline]
584    pub fn get_changed_tick(&self, row: TableRow) -> Option<&UnsafeCell<Tick>> {
585        self.changed_ticks.get(row.index())
586    }
587
588    /// Fetches the change detection ticks for the value at `row`.
589    ///
590    /// Returns `None` if `row` is out of bounds.
591    #[inline]
592    pub fn get_ticks(&self, row: TableRow) -> Option<ComponentTicks> {
593        if row.index() < self.data.len() {
594            // SAFETY: The size of the column has already been checked.
595            Some(unsafe { self.get_ticks_unchecked(row) })
596        } else {
597            None
598        }
599    }
600
601    /// Fetches the "added" change detection tick for the value at `row`. Unlike [`Column::get_added_tick`]
602    /// this function does not do any bounds checking.
603    ///
604    /// # Safety
605    /// `row` must be within the range `[0, self.len())`.
606    #[inline]
607    pub unsafe fn get_added_tick_unchecked(&self, row: TableRow) -> &UnsafeCell<Tick> {
608        debug_assert!(row.index() < self.added_ticks.len());
609        self.added_ticks.get_unchecked(row.index())
610    }
611
612    /// Fetches the "changed" change detection tick for the value at `row`. Unlike [`Column::get_changed_tick`]
613    /// this function does not do any bounds checking.
614    ///
615    /// # Safety
616    /// `row` must be within the range `[0, self.len())`.
617    #[inline]
618    pub unsafe fn get_changed_tick_unchecked(&self, row: TableRow) -> &UnsafeCell<Tick> {
619        debug_assert!(row.index() < self.changed_ticks.len());
620        self.changed_ticks.get_unchecked(row.index())
621    }
622
623    /// Fetches the change detection ticks for the value at `row`. Unlike [`Column::get_ticks`]
624    /// this function does not do any bounds checking.
625    ///
626    /// # Safety
627    /// `row` must be within the range `[0, self.len())`.
628    #[inline]
629    pub unsafe fn get_ticks_unchecked(&self, row: TableRow) -> ComponentTicks {
630        debug_assert!(row.index() < self.added_ticks.len());
631        debug_assert!(row.index() < self.changed_ticks.len());
632        ComponentTicks {
633            added: self.added_ticks.get_unchecked(row.index()).read(),
634            changed: self.changed_ticks.get_unchecked(row.index()).read(),
635        }
636    }
637
638    /// Clears the column, removing all values.
639    ///
640    /// Note that this function has no effect on the allocated capacity of the [`Column`]>
641    pub fn clear(&mut self) {
642        self.data.clear();
643        self.added_ticks.clear();
644        self.changed_ticks.clear();
645        self.changed_by.as_mut().map(Vec::clear);
646    }
647
648    #[inline]
649    pub(crate) fn check_change_ticks(&mut self, check: CheckChangeTicks) {
650        for component_ticks in &mut self.added_ticks {
651            component_ticks.get_mut().check_tick(check);
652        }
653        for component_ticks in &mut self.changed_ticks {
654            component_ticks.get_mut().check_tick(check);
655        }
656    }
657
658    /// Fetches the calling location that last changed the value at `row`.
659    ///
660    /// Returns `None` if `row` is out of bounds.
661    ///
662    /// Note: The values stored within are [`UnsafeCell`].
663    /// Users of this API must ensure that accesses to each individual element
664    /// adhere to the safety invariants of [`UnsafeCell`].
665    #[inline]
666    pub fn get_changed_by(
667        &self,
668        row: TableRow,
669    ) -> MaybeLocation<Option<&UnsafeCell<&'static Location<'static>>>> {
670        self.changed_by
671            .as_ref()
672            .map(|changed_by| changed_by.get(row.index()))
673    }
674
675    /// Fetches the calling location that last changed the value at `row`.
676    ///
677    /// Unlike [`Column::get_changed_by`] this function does not do any bounds checking.
678    ///
679    /// # Safety
680    /// `row` must be within the range `[0, self.len())`.
681    #[inline]
682    pub unsafe fn get_changed_by_unchecked(
683        &self,
684        row: TableRow,
685    ) -> MaybeLocation<&UnsafeCell<&'static Location<'static>>> {
686        self.changed_by.as_ref().map(|changed_by| {
687            debug_assert!(row.index() < changed_by.len());
688            changed_by.get_unchecked(row.index())
689        })
690    }
691
692    /// Returns the drop function for elements of the column,
693    /// or `None` if they don't need to be dropped.
694    #[inline]
695    pub fn get_drop(&self) -> Option<unsafe fn(OwningPtr<'_>)> {
696        self.data.get_drop()
697    }
698}