use alloc::borrow::ToOwned;
use core::marker::PhantomData;
use serde::{Deserialize, Serialize};
use crate::{
corpus::{Corpus, CorpusId},
impl_serdeany,
inputs::UsesInput,
schedulers::Scheduler,
state::{HasCorpus, HasMetadata, UsesState},
Error,
};
#[derive(Default, Clone, Copy, Eq, PartialEq, Debug, Serialize, Deserialize)]
struct TuneableSchedulerMetadata {
next: Option<CorpusId>,
}
impl_serdeany!(TuneableSchedulerMetadata);
#[derive(Debug, Clone)]
pub struct TuneableScheduler<S> {
phantom: PhantomData<S>,
}
impl<S> TuneableScheduler<S>
where
S: HasMetadata + HasCorpus,
{
#[must_use]
pub fn new(state: &mut S) -> Self {
if !state.has_metadata::<TuneableSchedulerMetadata>() {
state.add_metadata(TuneableSchedulerMetadata::default());
}
Self {
phantom: PhantomData,
}
}
fn metadata_mut(state: &mut S) -> &mut TuneableSchedulerMetadata {
state
.metadata_mut()
.get_mut::<TuneableSchedulerMetadata>()
.unwrap()
}
fn metadata(state: &S) -> &TuneableSchedulerMetadata {
state.metadata().get::<TuneableSchedulerMetadata>().unwrap()
}
pub fn set_next(state: &mut S, next: CorpusId) {
Self::metadata_mut(state).next = Some(next);
}
pub fn get_next(state: &S) -> Option<CorpusId> {
Self::metadata(state).next
}
pub fn reset(state: &mut S) {
let metadata = Self::metadata_mut(state);
metadata.next = None;
}
pub fn get_current(state: &S) -> CorpusId {
state
.corpus()
.current()
.unwrap_or_else(|| state.corpus().first().expect("Empty corpus"))
}
}
impl<S> UsesState for TuneableScheduler<S>
where
S: UsesInput,
{
type State = S;
}
impl<S> Scheduler for TuneableScheduler<S>
where
S: HasCorpus + HasMetadata,
{
fn next(&self, state: &mut Self::State) -> Result<CorpusId, Error> {
if state.corpus().count() == 0 {
return Err(Error::empty("No entries in corpus".to_owned()));
}
let id = if let Some(next) = Self::get_next(state) {
next
} else if let Some(next) = state.corpus().next(Self::get_current(state)) {
next
} else {
state.corpus().first().unwrap()
};
*state.corpus_mut().current_mut() = Some(id);
Ok(id)
}
}