use std::{ collections::{BTreeSet, HashMap}, marker::PhantomData, }; use libafl::{ corpus::{Corpus, CorpusId, Testcase}, feedbacks::MapNoveltiesMetadata, inputs::UsesInput, schedulers::{RemovableScheduler, Scheduler}, state::{HasCorpus, HasMetadata, UsesState, State}, Error, }; #[derive(Clone, Debug)] pub struct MergeScheduler { mapping: HashMap, all: BTreeSet, phantom: PhantomData, } impl UsesState for MergeScheduler where S: State, { type State = S; } impl RemovableScheduler for MergeScheduler where S: State + HasCorpus, { fn on_remove( &mut self, _state: &mut Self::State, idx: CorpusId, _testcase: &Option::Input>>, ) -> Result<(), Error> { self.all.remove(&idx); Ok(()) } } impl Scheduler for MergeScheduler where S: State + HasCorpus, { fn on_add(&mut self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> { self.all.insert(idx); let testcase = state.corpus().get(idx)?.borrow(); let meta = testcase.metadata::()?; for cov_idx in &meta.list { self.mapping.insert(*cov_idx, idx); } Ok(()) } fn next(&mut self, _state: &mut Self::State) -> Result { unimplemented!("Not suitable for actual scheduling."); } } impl MergeScheduler { pub fn new() -> Self { Self { mapping: HashMap::default(), all: BTreeSet::default(), phantom: PhantomData, } } pub fn removable(&self) -> BTreeSet { self.all .difference(&self.mapping.values().copied().collect()) .copied() .collect() } pub fn current(&self) -> &BTreeSet { &self.all } }