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