Skip to main content

luaur_analysis/methods/
frontend_send_queue_item_tasks.rs

1use crate::records::build_queue_work_state::{BuildQueueWorkState, Task};
2use crate::records::frontend::Frontend;
3use alloc::boxed::Box;
4use alloc::sync::Arc;
5use alloc::vec::Vec;
6use luaur_common::macros::luau_assert::LUAU_ASSERT;
7
8/// Captures the raw `Frontend`/`state` pointers that each queued task needs to run
9/// `performQueueItemTask`. C++ captures `this`, `state`, and `itemPos` by value into
10/// the `std::function<void()>`. The default (single-threaded) executor runs each task
11/// immediately on the calling thread, so the raw pointers stay valid; the `Send` marker
12/// is asserted to satisfy the `Task` bound, mirroring the C++ ownership model.
13struct TaskCapture {
14    frontend: *mut Frontend,
15    state: Arc<BuildQueueWorkState>,
16    item_pos: usize,
17}
18
19unsafe impl Send for TaskCapture {}
20
21impl Frontend {
22    pub fn send_queue_item_tasks(&mut self, state: Arc<BuildQueueWorkState>, items: Vec<usize>) {
23        let state_ptr = Arc::as_ptr(&state) as *mut BuildQueueWorkState;
24        let frontend_ptr: *mut Frontend = self;
25
26        let mut tasks: Vec<Task> = Vec::with_capacity(items.len());
27
28        for &item_pos in &items {
29            let queue_items = unsafe { &mut (*state_ptr).build_queue_items };
30            let item = &mut queue_items[item_pos];
31
32            LUAU_ASSERT!(!item.processing);
33            item.processing = true;
34
35            let capture = TaskCapture {
36                frontend: frontend_ptr,
37                state: state.clone(),
38                item_pos,
39            };
40
41            tasks.push(Box::new(move || {
42                let capture = capture;
43                unsafe {
44                    (*capture.frontend)
45                        .perform_queue_item_task(capture.state.clone(), capture.item_pos);
46                }
47            }));
48        }
49
50        unsafe {
51            (*state_ptr).processing += items.len();
52        }
53
54        // C++: `state->executeTasks(std::move(tasks));`
55        let execute_tasks_slot = unsafe { &(*state_ptr).execute_tasks };
56        let execute_tasks = execute_tasks_slot
57            .as_ref()
58            .expect("BuildQueueWorkState::executeTasks must be set");
59        execute_tasks(tasks);
60    }
61}