use enum_map::{Enum, EnumMap};
#[derive(Default, Debug)]
pub(crate) struct WorkerGoals {
current: Option<WorkerGoal>,
requests: EnumMap<WorkerGoal, bool>,
}
#[derive(Debug, Enum, Clone, Copy)]
pub(crate) enum WorkerGoal {
Gc,
StopForFork,
}
impl WorkerGoals {
pub fn set_request(&mut self, goal: WorkerGoal) -> bool {
if !self.requests[goal] {
self.requests[goal] = true;
true
} else {
false
}
}
pub fn poll_next_goal(&mut self) -> Option<WorkerGoal> {
for (goal, requested) in self.requests.iter_mut() {
if *requested {
*requested = false;
self.current = Some(goal);
probe!(mmtk, goal_set, goal);
return Some(goal);
}
}
None
}
pub fn current(&self) -> Option<WorkerGoal> {
self.current
}
pub fn on_current_goal_completed(&mut self) {
probe!(mmtk, goal_complete);
self.current = None
}
pub fn debug_is_requested(&self, goal: WorkerGoal) -> bool {
self.requests[goal]
}
}
#[cfg(test)]
mod tests {
use super::{WorkerGoal, WorkerGoals};
#[test]
fn test_poll_none() {
let mut goals = WorkerGoals::default();
let next_goal = goals.poll_next_goal();
assert!(next_goal.is_none());
assert!(goals.current().is_none());
}
#[test]
fn test_poll_one() {
let mut goals = WorkerGoals::default();
goals.set_request(WorkerGoal::StopForFork);
let next_goal = goals.poll_next_goal();
assert!(matches!(next_goal, Some(WorkerGoal::StopForFork)));
assert!(matches!(goals.current(), Some(WorkerGoal::StopForFork)));
}
#[test]
fn test_goals_priority() {
let mut goals = WorkerGoals::default();
goals.set_request(WorkerGoal::StopForFork);
goals.set_request(WorkerGoal::Gc);
let next_goal = goals.poll_next_goal();
assert!(matches!(next_goal, Some(WorkerGoal::Gc)));
assert!(matches!(goals.current(), Some(WorkerGoal::Gc)));
}
}