luaur_require/records/
navigation_context.rs1use crate::enums::navigate_result::NavigateResult;
2use crate::functions::convert_navigate_result::convert_navigate_result;
3use crate::records::runtime_luau_config_timer::RuntimeLuauConfigTimer;
4use crate::records::runtime_navigation_context::RuntimeNavigationContext;
5use alloc::string::String;
6use alloc::{ffi::CString, rc::Rc};
7use core::ffi::{c_int, c_void};
8use core::option::Option;
9use luaur_vm::functions::lua_getthreaddata::lua_getthreaddata;
10use luaur_vm::functions::lua_l_error_l::lua_l_error_l;
11use luaur_vm::functions::lua_setthreaddata::lua_setthreaddata;
12use luaur_vm::type_aliases::lua_state::lua_State;
13
14pub use crate::enums::config_behavior::ConfigBehavior;
15pub use crate::enums::config_status::ConfigStatus;
16
17#[allow(non_camel_case_types)]
18pub struct NavigationContext {
19 pub(crate) luau_config_init: Option<alloc::boxed::Box<dyn Fn(*mut core::ffi::c_void)>>,
20 pub(crate) luau_config_interrupt:
21 Option<unsafe extern "C-unwind" fn(l: *mut core::ffi::c_void, gc: core::ffi::c_int)>,
22}
23
24impl NavigationContext {
25 pub const NavigateResult: () = ();
26 pub const ConfigBehavior: () = ();
27 pub const ConfigStatus: () = ();
28}
29
30pub trait NavigationContextTrait {
31 fn reset_to_requirer(&mut self) -> NavigateResult;
32 fn jump_to_alias(&mut self, path: &str) -> NavigateResult;
33
34 fn to_alias_override(&mut self, _alias_unprefixed: &str) -> NavigateResult {
35 NavigateResult::NotFound
36 }
37
38 fn to_alias_fallback(&mut self, _alias_unprefixed: &str) -> NavigateResult {
39 NavigateResult::NotFound
40 }
41
42 fn to_parent(&mut self) -> NavigateResult;
43 fn to_child(&mut self, component: &str) -> NavigateResult;
44
45 fn get_config_status(&self) -> ConfigStatus {
46 ConfigStatus::Absent
47 }
48
49 fn get_config_behavior(&self) -> ConfigBehavior {
50 ConfigBehavior::GetAlias
51 }
52
53 fn get_alias(&self, _alias: &str) -> Option<String> {
54 None
55 }
56
57 fn get_config(&self) -> Option<String> {
58 None
59 }
60
61 fn luau_config_init(&self) -> Option<Rc<dyn Fn(*mut lua_State)>> {
62 None
63 }
64
65 fn luau_config_interrupt(
66 &self,
67 ) -> Option<unsafe extern "C-unwind" fn(l: *mut lua_State, gc: c_int)> {
68 None
69 }
70}
71
72impl NavigationContextTrait for NavigationContext {
73 fn reset_to_requirer(&mut self) -> NavigateResult {
74 NavigateResult::NotFound
75 }
76
77 fn jump_to_alias(&mut self, _path: &str) -> NavigateResult {
78 NavigateResult::NotFound
79 }
80
81 fn to_parent(&mut self) -> NavigateResult {
82 NavigateResult::NotFound
83 }
84
85 fn to_child(&mut self, _component: &str) -> NavigateResult {
86 NavigateResult::NotFound
87 }
88}
89
90impl NavigationContextTrait for RuntimeNavigationContext {
91 fn reset_to_requirer(&mut self) -> NavigateResult {
92 unsafe {
93 if self.config.is_null() {
94 return NavigateResult::NotFound;
95 }
96
97 let Some(reset) = (*self.config).reset else {
98 return NavigateResult::NotFound;
99 };
100
101 let Ok(requirer_chunkname) = CString::new(self.requirer_chunkname.as_str()) else {
102 return NavigateResult::NotFound;
103 };
104
105 convert_navigate_result(reset(self.l, self.ctx, requirer_chunkname.as_ptr()) as i32)
106 }
107 }
108
109 fn jump_to_alias(&mut self, path: &str) -> NavigateResult {
110 unsafe {
111 if self.config.is_null() {
112 return NavigateResult::NotFound;
113 }
114
115 let Some(jump_to_alias) = (*self.config).jump_to_alias else {
116 return NavigateResult::NotFound;
117 };
118
119 let Ok(path) = CString::new(path) else {
120 return NavigateResult::NotFound;
121 };
122
123 convert_navigate_result(jump_to_alias(self.l, self.ctx, path.as_ptr()) as i32)
124 }
125 }
126
127 fn to_alias_override(&mut self, alias_unprefixed: &str) -> NavigateResult {
128 unsafe {
129 if self.config.is_null() {
130 return NavigateResult::NotFound;
131 }
132
133 let Some(to_alias_override) = (*self.config).to_alias_override else {
134 return NavigateResult::NotFound;
135 };
136
137 let Ok(alias_unprefixed) = CString::new(alias_unprefixed) else {
138 return NavigateResult::NotFound;
139 };
140
141 convert_navigate_result(
142 to_alias_override(self.l, self.ctx, alias_unprefixed.as_ptr()) as i32,
143 )
144 }
145 }
146
147 fn to_alias_fallback(&mut self, alias_unprefixed: &str) -> NavigateResult {
148 unsafe {
149 if self.config.is_null() {
150 return NavigateResult::NotFound;
151 }
152
153 let Some(to_alias_fallback) = (*self.config).to_alias_fallback else {
154 return NavigateResult::NotFound;
155 };
156
157 let Ok(alias_unprefixed) = CString::new(alias_unprefixed) else {
158 return NavigateResult::NotFound;
159 };
160
161 convert_navigate_result(
162 to_alias_fallback(self.l, self.ctx, alias_unprefixed.as_ptr()) as i32,
163 )
164 }
165 }
166
167 fn to_parent(&mut self) -> NavigateResult {
168 RuntimeNavigationContext::to_parent(self)
169 }
170
171 fn to_child(&mut self, component: &str) -> NavigateResult {
172 unsafe {
173 if self.config.is_null() {
174 return NavigateResult::NotFound;
175 }
176
177 let Some(to_child) = (*self.config).to_child else {
178 return NavigateResult::NotFound;
179 };
180
181 let Ok(component) = CString::new(component) else {
182 return NavigateResult::NotFound;
183 };
184
185 convert_navigate_result(to_child(self.l, self.ctx, component.as_ptr()) as i32)
186 }
187 }
188
189 fn get_config_status(&self) -> ConfigStatus {
190 RuntimeNavigationContext::get_config_status(self)
191 }
192
193 fn get_config_behavior(&self) -> ConfigBehavior {
194 RuntimeNavigationContext::get_config_behavior(self)
195 }
196
197 fn get_alias(&self, alias: &str) -> Option<String> {
198 RuntimeNavigationContext::get_alias(self, alias)
199 }
200
201 fn get_config(&self) -> Option<String> {
202 RuntimeNavigationContext::get_config(self)
203 }
204
205 fn luau_config_init(&self) -> Option<Rc<dyn Fn(*mut lua_State)>> {
206 let config = self.config;
207 let ctx = self.ctx;
208 let timer = core::ptr::addr_of!(self.timer) as *mut RuntimeLuauConfigTimer as usize;
209
210 Some(Rc::new(move |l: *mut lua_State| unsafe {
211 let timeout = if !config.is_null() {
212 if let Some(get_timeout) = (*config).get_luau_config_timeout {
213 get_timeout(l as *mut c_void, ctx)
214 } else {
215 2000
216 }
217 } else {
218 2000
219 };
220
221 let timer = timer as *mut RuntimeLuauConfigTimer;
222 (*timer).start(timeout);
223 lua_setthreaddata(l, timer as *mut c_void);
224 }))
225 }
226
227 fn luau_config_interrupt(
228 &self,
229 ) -> Option<unsafe extern "C-unwind" fn(l: *mut lua_State, gc: c_int)> {
230 Some(runtime_luau_config_interrupt)
231 }
232}
233
234unsafe extern "C-unwind" fn runtime_luau_config_interrupt(l: *mut lua_State, _gc: c_int) {
235 let timer = lua_getthreaddata(l) as *const RuntimeLuauConfigTimer;
236 if !timer.is_null() && (*timer).is_finished() {
237 lua_l_error_l(
238 l,
239 c"configuration execution timed out".as_ptr(),
240 format_args!("configuration execution timed out"),
241 );
242 }
243}