1#[cfg(not(target_family = "wasm"))]
2use core::sync::atomic::{AtomicU8, Ordering};
3use core::{cell::UnsafeCell, ptr};
4
5use crate::__support::{Bounds, MovableBounds, SyncUnsafeCell};
6
7#[repr(C)]
10pub struct Section {
11 name: &'static str,
12 bounds: Bounds,
13}
14
15impl Section {
16 #[doc(hidden)]
21 pub const unsafe fn new(name: &'static str, bounds: Bounds) -> Self {
22 Self { name, bounds }
23 }
24
25 #[inline]
27 pub fn byte_len(&self) -> usize {
28 self.bounds.byte_len()
29 }
30
31 #[inline]
33 pub fn start_ptr(&self) -> *const () {
34 self.bounds.start_ptr()
35 }
36 #[inline]
38 pub fn end_ptr(&self) -> *const () {
39 self.bounds.end_ptr()
40 }
41
42 #[doc(hidden)]
44 pub const fn __validate<T: IsUntypedSection>(_section: &T) {}
45}
46
47impl ::core::fmt::Debug for Section {
48 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
49 f.debug_struct("Section")
50 .field("name", &self.name)
51 .field("start", &self.start_ptr())
52 .field("end", &self.end_ptr())
53 .field("byte_len", &self.byte_len())
54 .finish()
55 }
56}
57
58unsafe impl Sync for Section {}
59unsafe impl Send for Section {}
60
61pub trait IsUntypedSection {}
65
66macro_rules! impl_section_new {
67 ($generic:ident) => {
68 #[doc(hidden)]
73 pub const unsafe fn new(name: &'static str, bounds: Bounds) -> Self {
74 assert!(
75 ::core::mem::size_of::<$generic>() > 0,
76 "Zero-sized types are not supported"
77 );
78 Self {
79 name,
80 bounds,
81 _phantom: ::core::marker::PhantomData,
82 }
83 }
84 };
85}
86
87macro_rules! impl_bounds_fns {
88 ($generic:ident) => {
89 #[inline(always)]
91 pub fn start_ptr(&self) -> *const T {
92 self.bounds.start_ptr() as *const T
93 }
94
95 #[inline(always)]
97 pub fn end_ptr(&self) -> *const T {
98 self.bounds.end_ptr() as *const T
99 }
100
101 #[inline(always)]
103 pub const fn stride(&self) -> usize {
104 assert!(
105 ::core::mem::size_of::<T>() > 0
106 && ::core::mem::size_of::<T>() * 2 == ::core::mem::size_of::<[T; 2]>()
107 );
108 ::core::mem::size_of::<T>()
109 }
110
111 #[inline]
113 pub fn byte_len(&self) -> usize {
114 self.bounds.byte_len()
115 }
116
117 #[inline]
119 pub fn len(&self) -> usize {
120 self.byte_len() / self.stride()
121 }
122
123 #[inline]
125 pub fn is_empty(&self) -> bool {
126 self.len() == 0
127 }
128
129 #[inline]
131 pub fn as_slice(&self) -> &[T] {
132 if self.is_empty() {
133 &[]
134 } else {
135 unsafe { ::core::slice::from_raw_parts(self.start_ptr(), self.len()) }
136 }
137 }
138 };
139}
140
141macro_rules! impl_bounds_traits {
142 ($name:ident < $generic:ident >) => {
143 impl<'a, $generic> ::core::iter::IntoIterator for &'a $name<$generic> {
144 type Item = &'a $generic;
145 type IntoIter = ::core::slice::Iter<'a, $generic>;
146 fn into_iter(self) -> Self::IntoIter {
147 self.as_slice().iter()
148 }
149 }
150
151 impl<T> ::core::ops::Deref for $name<$generic> {
152 type Target = [$generic];
153 fn deref(&self) -> &Self::Target {
154 self.as_slice()
155 }
156 }
157
158 impl<T> ::core::fmt::Debug for $name<$generic> {
159 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
160 f.debug_struct(stringify!($name))
161 .field("name", &self.name)
162 .field("start", &self.start_ptr())
163 .field("end", &self.end_ptr())
164 .field("len", &self.len())
165 .field("stride", &self.stride())
166 .finish()
167 }
168 }
169
170 impl<T> $crate::__support::SectionItemType for $name<$generic> {
171 type Item = $generic;
172 }
173
174 impl<T> $crate::__support::SectionItemTyped<$generic> for $name<$generic> {
175 type Item = $generic;
176 }
177
178 unsafe impl<$generic> Sync for $name<$generic> where $generic: Sync {}
179 unsafe impl<$generic> Send for $name<$generic> where $generic: Send {}
180 };
181}
182
183#[repr(C)]
193pub struct TypedSection<T: 'static> {
194 name: &'static str,
195 bounds: Bounds,
196 _phantom: ::core::marker::PhantomData<T>,
197}
198
199impl<T: 'static> TypedSection<T> {
200 impl_section_new!(T);
201 impl_bounds_fns!(T);
202
203 #[inline]
205 pub fn offset_of(&self, item: &T) -> Option<usize> {
206 let ptr = item as *const T;
207 if ptr < self.start_ptr() || ptr >= self.end_ptr() {
208 None
209 } else {
210 Some(unsafe { ptr.offset_from(self.start_ptr()) as usize })
211 }
212 }
213}
214
215impl_bounds_traits!(TypedSection<T>);
216
217#[repr(C)]
226pub struct TypedMutableSection<T: 'static> {
227 name: &'static str,
228 bounds: Bounds,
229 _phantom: ::core::marker::PhantomData<T>,
230}
231
232impl<T: 'static> TypedMutableSection<T> {
233 impl_section_new!(T);
234 impl_bounds_fns!(T);
235
236 #[inline]
238 pub fn offset_of(&self, item: &T) -> Option<usize> {
239 let ptr = item as *const T;
240 if ptr < self.start_ptr() || ptr >= self.end_ptr() {
241 None
242 } else {
243 Some(unsafe { ptr.offset_from(self.start_ptr()) as usize })
244 }
245 }
246
247 #[inline]
249 pub fn start_ptr_mut(&self) -> *mut T {
250 self.bounds.start_ptr() as *mut T
251 }
252
253 #[inline]
255 pub fn end_ptr_mut(&self) -> *mut T {
256 self.bounds.end_ptr() as *mut T
257 }
258
259 #[allow(clippy::mut_from_ref)]
266 #[inline]
267 pub unsafe fn as_mut_slice(&self) -> &mut [T] {
268 if self.is_empty() {
269 &mut []
270 } else {
271 unsafe { ::core::slice::from_raw_parts_mut(self.start_ptr() as *mut T, self.len()) }
272 }
273 }
274}
275
276impl_bounds_traits!(TypedMutableSection<T>);
277
278#[repr(C)]
291pub struct TypedMovableSection<T: 'static> {
292 name: &'static str,
293 bounds: MovableBounds,
294 #[cfg(not(target_family = "wasm"))]
295 backref_state: AtomicU8,
296 _phantom: ::core::marker::PhantomData<T>,
297}
298
299impl<T: 'static> TypedMovableSection<T> {
300 #[doc(hidden)]
305 pub const unsafe fn new(name: &'static str, bounds: MovableBounds) -> Self {
306 assert!(
307 ::core::mem::size_of::<T>() > 0,
308 "Zero-sized types are not supported"
309 );
310 Self {
311 name,
312 bounds,
313 #[cfg(not(target_family = "wasm"))]
314 backref_state: AtomicU8::new(0),
315 _phantom: ::core::marker::PhantomData,
316 }
317 }
318
319 impl_bounds_fns!(T);
320
321 #[inline]
323 pub fn offset_of(&self, item: &T) -> Option<usize> {
324 let ptr = item as *const T;
325 if ptr < self.start_ptr() || ptr >= self.end_ptr() {
326 None
327 } else {
328 Some(unsafe { ptr.offset_from(self.start_ptr()) as usize })
329 }
330 }
331
332 #[allow(clippy::mut_from_ref)]
339 #[inline]
340 pub unsafe fn as_mut_slice(&self) -> &mut [T] {
341 if self.is_empty() {
342 &mut []
343 } else {
344 unsafe { ::core::slice::from_raw_parts_mut(self.start_ptr() as *mut T, self.len()) }
345 }
346 }
347
348 #[allow(clippy::mut_from_ref)]
358 #[inline]
359 pub unsafe fn as_mut_backrefs(&self) -> &mut [MovableBackref<T>] {
360 let backrefs_len =
361 self.bounds.backrefs_byte_len() / ::core::mem::size_of::<MovableBackref<T>>();
362 let backrefs = if backrefs_len == 0 {
363 &mut []
364 } else {
365 unsafe {
366 ::core::slice::from_raw_parts_mut(
367 self.bounds.backrefs_start_ptr() as *mut MovableBackref<T>,
368 backrefs_len,
369 )
370 }
371 };
372 #[cfg(not(target_family = "wasm"))]
373 unsafe {
374 self.fixup_backrefs(backrefs)
375 };
376 backrefs
377 }
378
379 #[cfg(not(target_family = "wasm"))]
385 unsafe fn fixup_backrefs(&self, backrefs: &mut [MovableBackref<T>]) {
386 match self
387 .backref_state
388 .compare_exchange(0, 1, Ordering::Acquire, Ordering::Acquire)
389 {
390 Ok(_) => {}
391 Err(2) => return,
392 Err(_) => panic!("movable section backrefs already being initialized"),
393 }
394
395 if backrefs.len() != self.len() {
396 panic!("movable section backref count does not match item count");
397 }
398
399 backrefs.sort_unstable_by_key(|backref| backref.current_ptr());
400 self.backref_state.store(2, Ordering::Release);
401 }
402
403 #[allow(unsafe_code)]
415 pub unsafe fn sort_unstable(&self)
416 where
417 T: Ord,
418 {
419 let main = unsafe { self.as_mut_slice() };
421 if main.len() <= 1 {
422 return;
423 }
424
425 let refs = unsafe { self.as_mut_backrefs() };
426 debug_assert_eq!(main.len(), refs.len());
427
428 fn partition<T: Ord, R>(main: &mut [T], refs: &mut [R]) -> usize {
429 let n = main.len();
430 if n == 0 {
431 return 0;
432 }
433 let pivot = n - 1;
434 let mut i = 0;
435 for j in 0..pivot {
436 if main[j] <= main[pivot] {
437 main.swap(i, j);
438 refs.swap(i, j);
439 i += 1;
440 }
441 }
442 main.swap(i, pivot);
443 refs.swap(i, pivot);
444 i
445 }
446
447 fn recurse<T: Ord, R>(main: &mut [T], refs: &mut [R]) {
448 let n = main.len();
449 if n <= 1 {
450 return;
451 }
452 let p = partition(main, refs);
453 let (ml, mr) = main.split_at_mut(p);
454 let (rl, rr) = refs.split_at_mut(p);
455 recurse(ml, rl);
456 if mr.len() > 1 {
457 recurse(&mut mr[1..], &mut rr[1..]);
458 }
459 }
460
461 recurse(main, refs);
462
463 for (item, backref) in main.iter().zip(refs.iter()) {
465 unsafe {
466 backref.set_current_ptr(item as *const T);
467 }
468 }
469 }
470}
471
472impl_bounds_traits!(TypedMovableSection<T>);
473
474#[repr(transparent)]
480pub struct MovableRef<T: 'static> {
481 slot: SyncUnsafeCell<*const T>,
482}
483
484impl<T> MovableRef<T> {
485 #[doc(hidden)]
486 pub const fn new(ptr: *const T) -> Self {
487 Self {
488 slot: SyncUnsafeCell::new(ptr),
489 }
490 }
491
492 #[doc(hidden)]
495 pub const fn slot_ptr(this: *const Self) -> *const UnsafeCell<*const T> {
496 this.cast::<UnsafeCell<*const T>>()
497 }
498
499 pub fn as_ptr(&self) -> *const T {
501 unsafe { *self.slot.get() }
502 }
503}
504
505impl<T> ::core::ops::Deref for MovableRef<T> {
506 type Target = T;
507 fn deref(&self) -> &Self::Target {
508 unsafe { self.as_ptr().as_ref().expect("MovableRef not initialized") }
509 }
510}
511
512unsafe impl<T> Send for MovableRef<T> where T: Send {}
513unsafe impl<T> Sync for MovableRef<T> where T: Sync {}
514
515#[repr(C)]
518pub struct MovableBackref<T: 'static> {
519 slot: *const UnsafeCell<*const T>,
520}
521
522impl<T> MovableBackref<T> {
523 #[doc(hidden)]
524 pub const fn new(slot: *const UnsafeCell<*const T>) -> Self {
525 Self { slot }
526 }
527
528 pub fn current_ptr(&self) -> *const T {
530 unsafe { ptr::read(UnsafeCell::raw_get(self.slot)) }
531 }
532
533 pub unsafe fn set_current_ptr(&self, ptr: *const T) {
541 unsafe {
542 ptr::write(UnsafeCell::raw_get(self.slot), ptr);
543 }
544 }
545}
546
547unsafe impl<T> Send for MovableBackref<T> where T: Send {}
548unsafe impl<T> Sync for MovableBackref<T> where T: Sync {}
549
550#[repr(C)]
553pub struct TypedReferenceSection<T: 'static> {
554 name: &'static str,
555 bounds: Bounds,
556 _phantom: ::core::marker::PhantomData<T>,
557}
558
559impl<T: 'static> TypedReferenceSection<T> {
560 impl_section_new!(T);
561 impl_bounds_fns!(T);
562
563 #[inline]
565 pub fn offset_of(&self, item: &Ref<T>) -> Option<usize> {
566 let ptr = item.as_ptr();
567 if ptr < self.start_ptr() || ptr >= self.end_ptr() {
568 None
569 } else {
570 Some(unsafe { ptr.offset_from(self.start_ptr()) as usize })
571 }
572 }
573}
574
575impl_bounds_traits!(TypedReferenceSection<T>);
576
577#[repr(transparent)]
581pub struct Ref<T: 'static> {
582 #[cfg(target_family = "wasm")]
583 ptr: ::core::cell::UnsafeCell<*const T>,
584 #[cfg(not(target_family = "wasm"))]
585 t: T,
586}
587
588impl<T> Ref<T> {
589 #[cfg(not(target_family = "wasm"))]
590 #[doc(hidden)]
591 pub const fn new(t: T) -> Self {
592 Self { t }
593 }
594
595 #[cfg(target_family = "wasm")]
596 #[doc(hidden)]
597 pub const fn new() -> Self {
598 Self {
599 ptr: ::core::cell::UnsafeCell::new(::core::ptr::null()),
600 }
601 }
602
603 #[cfg(target_family = "wasm")]
609 #[doc(hidden)]
610 pub unsafe fn set(&self, ptr: *const T) {
611 *self.ptr.get() = ptr;
612 }
613
614 pub fn as_ptr(&self) -> *const T {
616 #[cfg(target_family = "wasm")]
617 {
618 unsafe { *self.ptr.get() }
619 }
620 #[cfg(not(target_family = "wasm"))]
621 {
622 &self.t as *const T
623 }
624 }
625}
626
627impl<T> ::core::ops::Deref for Ref<T> {
628 type Target = T;
629 fn deref(&self) -> &Self::Target {
630 #[cfg(target_family = "wasm")]
631 unsafe {
632 ::core::ptr::read(self.ptr.get())
633 .as_ref()
634 .expect("Ref not initialized")
635 }
636 #[cfg(not(target_family = "wasm"))]
637 &self.t
638 }
639}
640
641unsafe impl<T> Send for Ref<T> where T: Send {}
642unsafe impl<T> Sync for Ref<T> where T: Sync {}