rune/no_std/mod.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
//! Public types related to using rune in #[no_std] environments.
use core::ptr::NonNull;
/// Environment that needs to be stored somewhere.
#[derive(Clone, Copy)]
#[repr(C)]
pub struct RawEnv {
pub(crate) context: Option<NonNull<()>>,
pub(crate) unit: Option<NonNull<()>>,
pub(crate) diagnostics: Option<NonNull<()>>,
}
impl RawEnv {
/// Initialize an empty raw environment.
pub const fn null() -> RawEnv {
RawEnv {
context: None,
unit: None,
diagnostics: None,
}
}
}
/// Defines a static budget and environment implementation suitable for
/// singlethreaded no-std environments. This can be used in `#[no_std]`
/// environments to implement the necessary hooks for Rune to work.
///
/// The alternative is to implement these manually.
///
/// If the `std` feature is enabled, thread-local budgeting will be used and
/// calling this will do nothing.
///
/// # Examples
///
/// ```
/// rune::no_std::static_env!();
/// ```
#[macro_export]
macro_rules! static_env {
() => {
$crate::no_std::__static_env!();
};
}
#[cfg(feature = "std")]
#[macro_export]
#[doc(hidden)]
macro_rules! __static_env {
() => {};
}
#[cfg(not(feature = "std"))]
#[macro_export]
#[doc(hidden)]
macro_rules! __static_env {
() => {
const _: () = {
use $crate::no_std::RawEnv;
static mut BUDGET: usize = usize::MAX;
static mut MEMORY: usize = usize::MAX;
static mut RAW_ENV: RawEnv = RawEnv::null();
/// Necessary hook to abort the current process.
#[no_mangle]
extern "C" fn __rune_alloc_abort() -> ! {
::core::intrinsics::abort()
}
#[no_mangle]
extern "C" fn __rune_alloc_memory_take(amount: usize) -> bool {
unsafe {
if MEMORY == usize::MAX {
return true;
}
if MEMORY >= amount {
MEMORY -= amount;
return true;
}
return false;
}
}
/// Release the given amount of memory to the current budget.
#[no_mangle]
extern "C" fn __rune_alloc_memory_release(amount: usize) {
unsafe {
if MEMORY == usize::MAX {
return;
}
MEMORY = MEMORY.saturating_add(amount);
}
}
/// Get the remaining memory budget for the current thread.
#[no_mangle]
extern "C" fn __rune_alloc_memory_get() -> usize {
unsafe { MEMORY }
}
/// Replace the memory budget for the current thread and return the one which
/// was previously set.
#[no_mangle]
extern "C" fn __rune_alloc_memory_replace(value: usize) -> usize {
unsafe { core::ptr::replace(core::ptr::addr_of_mut!(MEMORY), value) }
}
#[no_mangle]
extern "C" fn __rune_budget_replace(value: usize) -> usize {
// SAFETY: this is only ever executed in a singlethreaded environment.
unsafe { core::ptr::replace(core::ptr::addr_of_mut!(BUDGET), value) }
}
#[no_mangle]
extern "C" fn __rune_budget_get() -> usize {
// SAFETY: this is only ever executed in a singlethreaded environment.
unsafe { BUDGET }
}
#[no_mangle]
extern "C" fn __rune_env_get() -> RawEnv {
// SAFETY: this is only ever executed in a singlethreaded environment.
unsafe { RAW_ENV }
}
#[no_mangle]
extern "C" fn __rune_env_replace(env: RawEnv) -> RawEnv {
// SAFETY: this is only ever executed in a singlethreaded environment.
unsafe { core::ptr::replace(core::ptr::addr_of_mut!(RAW_ENV), env) }
}
};
};
}
#[doc(hidden)]
pub use __static_env;
#[doc(inline)]
pub use static_env;