#![recursion_limit = "256"]
#![no_std]
#![doc = include_str!("../docs/BUILD.md")]
#![doc = include_str!("../docs/PREAMBLE.md")]
#![doc = include_str!("../docs/GENERATED.md")]
#![cfg_attr(
all(target_vendor = "apple", linktime_used_linker),
feature(used_with_arg)
)]
#![cfg_attr(linktime_used_linker, doc(test(attr(feature(used_with_arg)))))]
#[cfg(feature = "std")]
extern crate std;
mod macros;
mod parse;
mod priority;
#[cfg(target_os = "aix")]
mod priority_aix;
pub mod statics;
#[doc = include_str!("../docs/LIFE_BEFORE_MAIN.md")]
pub mod life_before_main {}
#[doc(hidden)]
#[allow(unused)]
pub mod __support {
pub use crate::__ctor_parse as ctor_parse;
#[cfg(all(feature = "priority", target_vendor = "apple"))]
pub use link_section::declarative::in_section;
}
#[cfg(all(feature = "priority", target_vendor = "apple"))]
crate::__ctor_parse_internal!(
__ctor_features,
#[ctor(unsafe, naked)]
#[allow(unsafe_code)]
fn priority_ctor() {
unsafe {
crate::collect::run_constructors();
}
}
);
#[cfg(all(feature = "priority", target_vendor = "apple"))]
#[doc(hidden)]
pub mod collect {
use core::sync::atomic::{AtomicU8, Ordering};
#[doc(hidden)]
pub const PROCESSED: isize = isize::MIN;
#[doc(hidden)]
pub const LATE: isize = isize::MAX;
const GUARD_NOT_RUN: u8 = 0;
const GUARD_RUNNING: u8 = 1;
const GUARD_FINISHED: u8 = 2;
#[derive(Copy, Clone)]
#[repr(C)]
pub struct Constructor {
pub priority: isize,
pub ctor: unsafe extern "C" fn(),
}
#[allow(unsafe_code)]
pub(crate) unsafe fn run_constructors() {
let Some(guard) = _CTR0GR_ISIZE_FN.first() else {
return;
};
loop {
match guard.compare_exchange_weak(
GUARD_NOT_RUN,
GUARD_RUNNING,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => break,
Err(GUARD_NOT_RUN) => {
continue;
}
Err(_) => return,
}
}
unsafe {
let slice = _CTOR0_ISIZE_FN.as_mut_slice();
slice.sort_unstable_by_key(|constructor| constructor.priority);
}
unsafe {
let start = _CTOR0_ISIZE_FN.start_ptr_mut();
let end = _CTOR0_ISIZE_FN.end_ptr_mut();
let mut ptr = start;
while ptr < end {
let mut constructor = ptr.read();
if constructor.priority != crate::collect::PROCESSED {
constructor.priority = crate::collect::PROCESSED;
ptr.write(constructor);
(constructor.ctor)();
}
ptr = ptr.add(1);
}
}
guard.store(GUARD_FINISHED, Ordering::Release);
}
#[doc(hidden)]
link_section::declarative::section!(
#[section(no_macro)]
pub static _CTOR0_ISIZE_FN: link_section::TypedSection<Constructor>;
);
#[macro_export]
#[doc(hidden)]
macro_rules! __register_ctor {
(priority = (), fn = $fn:ident) => {
$crate::__register_ctor!(priority = ($crate::collect::EARLY), fn = $fn);
};
(priority = early, fn = $fn:ident) => {
$crate::__register_ctor!(priority = ($crate::collect::EARLY), fn = $fn);
};
(priority = late, fn = $fn:ident) => {
$crate::__register_ctor!(priority = ($crate::collect::LATE), fn = $fn);
};
(priority = $priority:tt, fn = $fn:ident) => {
$crate::__support::in_section!(
#[in_section(unsafe, type = $crate::collect::Constructor, name = _CTOR0_ISIZE_FN)]
pub const _: $crate::collect::Constructor = $crate::collect::Constructor {
priority: $priority,
ctor: $fn,
};
);
};
(priority = $priority:tt, fn = (array $array:ident)) => {
$crate::__support::in_section!(
#[in_section(unsafe, type = [$crate::collect::Constructor; if $array.len() == 0 { 1 } else { $array.len() }], name = _CTOR0_ISIZE_FN)]
pub const _: [$crate::collect::Constructor; if $array.len() == 0 { 1 } else { $array.len() }] = {
use core::mem::MaybeUninit;
if $array.len() == 0 {
unsafe extern "C" fn empty_ctor() {}
[$crate::collect::Constructor {
priority: $crate::collect::PROCESSED,
ctor: empty_ctor,
}; if $array.len() == 0 { 1 } else { $array.len() }]
} else {
let mut array: MaybeUninit<[$crate::collect::Constructor; if $array.len() == 0 { 1 } else { $array.len() }]> = MaybeUninit::uninit();
let mut array_ptr: *mut $crate::collect::Constructor = array.as_mut_ptr() as _;
const fn ctor_fn(i: usize) -> $crate::collect::Constructor {
$crate::collect::Constructor {
priority: $priority,
ctor: $array[i],
}
}
let mut i = 0;
while i < $array.len() {
unsafe { array_ptr.add(i).write(ctor_fn(i)) };
i += 1;
}
unsafe { array.assume_init() }
}
};
);
};
}
#[doc(hidden)]
link_section::declarative::section!(
#[section(no_macro)]
pub static _CTR0GR_ISIZE_FN: link_section::TypedSection<AtomicU8>;
);
link_section::declarative::in_section!(
#[in_section(unsafe, type = AtomicU8, name = _CTR0GR_ISIZE_FN)]
pub static GUARD_ATOMIC: AtomicU8 = AtomicU8::new(GUARD_NOT_RUN);
);
}
pub mod declarative {
#[doc(inline)]
pub use crate::__support::ctor_parse as ctor;
}
#[doc(inline)]
#[cfg(feature = "proc_macro")]
pub use ::linktime_proc_macro::ctor;
__declare_features!(
ctor: __ctor_features;
anonymous {
attr: [(anonymous) => (anonymous)];
};
body_link_section {
attr: [(body(link_section = $body_section:literal)) => ($body_section)];
example: "body(link_section = \".text.startup\")";
default {
(target_os = "linux") => ".text.startup",
(target_os = "android") => ".text.startup",
(target_os = "freebsd") => ".text.startup",
(all(target_vendor = "pc", any(target_env = "gnu", target_env = "msvc"))) => ".text$A",
(all(target_vendor = "pc", not(any(target_env = "gnu", target_env = "msvc")))) => ".text.startup",
(target_vendor = "apple") => "__TEXT,__text_startup,regular,pure_instructions",
_ => ()
}
};
crate_path {
attr: [(crate_path = $path:pat) => (($path))];
example: "crate_path = ::path::to::ctor::crate";
};
export_name_prefix {
attr: [(export_name_prefix = $export_name_prefix_str:literal) => ($export_name_prefix_str)];
example: "export_name_prefix = \"ctor_\"";
default {
(target_os = "aix") => "__sinit",
_ => (),
}
};
link_section {
attr: [(link_section = $section:literal) => ($section)];
example: "link_section = \".ctors\"";
default {
(target_vendor = "apple") => "__DATA,__mod_init_func,mod_init_funcs",
(any(
target_os = "linux",
target_os = "android",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
target_os = "dragonfly",
target_os = "illumos",
target_os = "haiku",
target_os = "vxworks",
target_os = "nto",
target_family = "wasm"
)) => ".init_array",
(target_os = "none") => ".init_array",
(target_arch = "xtensa") => ".ctors",
(all(target_vendor = "pc", any(target_env = "gnu", target_env = "msvc"))) => ".CRT$XCU",
(all(target_vendor = "pc", not(any(target_env = "gnu", target_env = "msvc")))) => ".ctors",
(all(target_os = "aix")) => (), _ => (compile_error!("Unsupported target for #[ctor]"))
}
};
naked {
attr: [(naked) => (naked)];
};
priority {
attr: [(priority = $priority_value:tt) => ($priority_value)];
example: "priority = N | early | late";
validate: [($priority:literal), (early), (late), (default)];
default {
(feature = "priority") => default,
_ => ()
}
};
priority_enabled {
feature: "priority";
};
proc_macro {
feature: "proc_macro";
};
std {
feature: "std";
};
r#unsafe {
attr: [(unsafe) => (no_fail_on_missing_unsafe)];
default {
(linktime_no_fail_on_missing_unsafe) => (no_fail_on_missing_unsafe),
_ => (),
}
};
used_linker {
attr: [(used(linker)) => (used_linker)];
default {
(linktime_used_linker) => used_linker,
_ => (),
}
};
);
#[cfg(doc)]
__generate_docs!(__ctor_features);