pub mod apple;
pub mod standard;
pub mod wasm;
pub mod windows;
#[cfg(target_vendor = "apple")]
pub use apple::{get_section, section_name};
#[cfg(all(
not(target_family = "wasm"),
not(target_os = "windows"),
not(target_vendor = "apple")
))]
pub use standard::{get_section, section_name};
#[cfg(target_family = "wasm")]
pub use wasm::{get_section, section_name};
#[cfg(target_os = "windows")]
pub use windows::{get_section, section_name};
#[cfg(target_family = "wasm")]
pub use wasm::{Bounds, MovableBounds, MovableRefStorage, RefStorage};
#[cfg(not(target_family = "wasm"))]
pub use {PtrBounds as Bounds, PtrMovableBounds as MovableBounds};
pub const fn validate_section_name(name: &str) {
if cfg!(target_vendor = "apple") {
apple::validate_apple_section_name(name);
}
if cfg!(all(
not(target_family = "wasm"),
not(target_os = "windows"),
not(target_vendor = "apple")
)) {
standard::is_valid_section_name(name);
}
}
pub fn launder_pointer_provenance<T>(ptr: *const T) -> *const T {
#[cfg(not(windows))]
{
core::ptr::with_exposed_provenance(ptr.expose_provenance())
}
#[cfg(windows)]
{
core::hint::black_box(core::ptr::with_exposed_provenance(ptr.expose_provenance()))
}
}
#[derive(Clone, Copy)]
pub struct SectionRange {
start: *const (),
end: *const (),
}
impl SectionRange {
#[inline(always)]
pub const fn new(start: *const (), end: *const ()) -> Self {
Self { start, end }
}
#[inline(always)]
pub const fn start_ptr(&self) -> *const () {
self.start
}
#[inline(always)]
pub const fn end_ptr(&self) -> *const () {
self.end
}
#[inline(always)]
pub fn byte_len(&self) -> usize {
self.end.addr() - self.start.addr()
}
#[inline]
pub unsafe fn slice_of<'a, T>(self, stride: usize) -> &'a [T] {
let len = self.byte_len() / stride;
if len == 0 {
&[]
} else {
unsafe { ::core::slice::from_raw_parts(self.start as *const T, len) }
}
}
#[inline]
pub unsafe fn slice_of_mut<'a, T>(self, stride: usize) -> &'a mut [T] {
let len = self.byte_len() / stride;
if len == 0 {
&mut []
} else {
unsafe { ::core::slice::from_raw_parts_mut(self.start as *mut T, len) }
}
}
}
pub struct PtrBounds {
pub start: *const (),
pub end: *const (),
}
impl PtrBounds {
pub const fn new(start: *const (), end: *const ()) -> Self {
Self { start, end }
}
#[inline(always)]
pub fn range(&self) -> SectionRange {
let start = launder_pointer_provenance(self.start);
let byte_len = self.end.addr() - self.start.addr();
let end = unsafe { (start as *const u8).add(byte_len) as *const () };
SectionRange::new(start, end)
}
}
pub struct PtrMovableBounds {
values: PtrBounds,
refs: PtrBounds,
}
impl PtrMovableBounds {
pub const fn new(values: PtrBounds, refs: PtrBounds) -> Self {
Self { values, refs }
}
#[inline(always)]
pub fn range(&self) -> SectionRange {
self.values.range()
}
#[inline(always)]
pub fn backrefs_range(&self) -> SectionRange {
self.refs.range()
}
}
#[repr(transparent)]
pub struct SyncUnsafeCell<T> {
#[allow(unused)]
cell: ::core::cell::UnsafeCell<T>,
}
impl<T> SyncUnsafeCell<T> {
pub const fn new(value: T) -> Self {
Self {
cell: ::core::cell::UnsafeCell::new(value),
}
}
#[inline]
pub const fn get(&self) -> *mut T {
self.cell.get()
}
}
unsafe impl<T> Sync for SyncUnsafeCell<T> {}
unsafe impl<T> Send for SyncUnsafeCell<T> {}
#[cfg(not(target_family = "wasm"))]
#[repr(C)]
pub struct RefStorage<T: 'static> {
t: T,
}
#[cfg(not(target_family = "wasm"))]
impl<T> RefStorage<T> {
pub const fn new(t: T) -> Self {
Self { t }
}
pub fn as_ptr(&self) -> *const T {
&self.t as *const T
}
pub fn get(&self) -> &T {
&self.t
}
}
#[cfg(not(target_family = "wasm"))]
#[repr(C)]
pub struct MovableRefStorage<T: 'static> {
slot: SyncUnsafeCell<*const T>,
}
#[cfg(not(target_family = "wasm"))]
impl<T> MovableRefStorage<T> {
pub const fn new(ptr: *const T) -> Self {
Self {
slot: SyncUnsafeCell::new(ptr),
}
}
pub const fn as_ptr(&self) -> *const T {
unsafe { *self.slot.get() }
}
pub fn get(&self) -> &T {
unsafe { self.as_ptr().as_ref().expect("MovableRef not initialized") }
}
}
#[repr(C)]
pub struct Alignment<T> {
_align: [T; 0],
_padding: u8,
}
#[allow(clippy::new_without_default)]
impl<T> Alignment<T> {
pub const fn new() -> Self {
Self {
_align: [],
_padding: 0,
}
}
}
#[macro_export]
#[doc(hidden)]
macro_rules! __def_section_name {
(
$__name:ident,
{$(
$__section:ident $__type:ident => $__prefix:tt __ $__suffix:tt;
)*}
AUXILIARY = $__aux_sep:literal;
REFS = $__refs_sep:literal;
MAX_LENGTH = $__max_length:literal;
HASH_LENGTH = $__hash_length:literal;
VALID_SECTION_CHARS = $__valid_section_chars:literal;
) => {
mod $__name {
#[macro_export]
#[doc(hidden)]
macro_rules! $__name {
$(
(string item $__section $__type ($name:tt () $unsafe:tt)) => {
$crate::__support::hash!($unsafe ($__prefix) ($name) ($__suffix) $__hash_length $__max_length $__valid_section_chars)
};
(string item $__section $__type ($aux:tt $name:tt $unsafe:tt)) => {
$crate::__support::hash!($unsafe ($__prefix) ($name $__aux_sep $aux) ($__suffix) $__hash_length $__max_length $__valid_section_chars)
};
(string backref $__section $__type ($name:tt () $unsafe:tt)) => {
$crate::__support::hash!($unsafe ($__prefix) ($name $__refs_sep) ($__suffix) $__hash_length $__max_length $__valid_section_chars)
};
(string backref $__section $__type ($aux:tt $name:tt $unsafe:tt)) => {
$crate::__support::hash!($unsafe ($__prefix) ($name $__aux_sep $aux $__refs_sep) ($__suffix) $__hash_length $__max_length $__valid_section_chars)
};
)*
($pattern:tt $unknown_ref_or_item:ident $unknown_section:ident $unknown_type:ident $name:ident) => {
const _: () = {
compile_error!(concat!("Unknown section type: `", stringify!($unknown_ref_or_item), "/", stringify!($unknown_section), "/", stringify!($unknown_type), "`"));
}
};
}
pub use $__name as section_name;
}
pub use $__name::section_name;
pub(crate) const MAX_LENGTH: usize = $__max_length;
pub(crate) const VALID_SECTION_CHARS: &[u8] = $__valid_section_chars.as_bytes();
#[allow(unused)]
pub(crate) const fn is_valid_section_char(b: u8) -> bool {
let mut i = 0;
while i < VALID_SECTION_CHARS.len() {
if VALID_SECTION_CHARS[i] == b {
return true;
}
i += 1;
}
false
}
#[allow(unused)]
pub(crate) const fn is_valid_section_name(name: &str) -> bool {
let bytes = name.as_bytes();
if bytes.is_empty() || bytes.len() > MAX_LENGTH {
return false;
}
let mut i = 0;
while i < bytes.len() {
let b = bytes[i];
if !is_valid_section_char(b) {
return false;
}
i += 1;
}
true
}
};
}