use core::{cell::RefCell, fmt, marker::PhantomData};
use serde::{Deserialize, Serialize};
use crate::Error;
pub mod testcase;
pub use testcase::{HasTestcase, SchedulerTestcaseMetadata, Testcase};
pub mod inmemory;
pub use inmemory::InMemoryCorpus;
pub mod dynamic;
pub use dynamic::DynamicCorpus;
#[cfg(feature = "std")]
pub mod inmemory_ondisk;
#[cfg(feature = "std")]
pub use inmemory_ondisk::InMemoryOnDiskCorpus;
#[cfg(feature = "std")]
pub mod ondisk;
#[cfg(feature = "std")]
pub use ondisk::OnDiskCorpus;
#[cfg(feature = "std")]
pub mod cached;
#[cfg(feature = "std")]
pub use cached::CachedOnDiskCorpus;
#[cfg(feature = "cmin")]
pub mod minimizer;
pub mod nop;
#[cfg(feature = "cmin")]
pub use minimizer::*;
pub use nop::NopCorpus;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
#[repr(transparent)]
pub struct CorpusId(pub usize);
impl fmt::Display for CorpusId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<usize> for CorpusId {
fn from(id: usize) -> Self {
Self(id)
}
}
impl From<u64> for CorpusId {
fn from(id: u64) -> Self {
Self(id as usize)
}
}
impl From<CorpusId> for usize {
fn from(id: CorpusId) -> Self {
id.0
}
}
#[macro_export]
macro_rules! random_corpus_id {
($corpus:expr, $rand:expr) => {{
let cnt = $corpus.count();
#[cfg(debug_assertions)]
let nth = $rand.below(core::num::NonZero::new(cnt).expect("Corpus may not be empty!"));
#[cfg(not(debug_assertions))]
let nth = $rand.below(unsafe { core::num::NonZero::new(cnt).unwrap_unchecked() });
$corpus.nth(nth)
}};
}
#[macro_export]
macro_rules! random_corpus_id_with_disabled {
($corpus:expr, $rand:expr) => {{
let cnt = $corpus.count_all();
#[cfg(debug_assertions)]
let nth = $rand.below(core::num::NonZero::new(cnt).expect("Corpus may not be empty!"));
#[cfg(not(debug_assertions))]
let nth = $rand.below(unsafe { core::num::NonZero::new(cnt).unwrap_unchecked() });
$corpus.nth_from_all(nth)
}};
}
pub trait Corpus<I>: Sized {
fn count(&self) -> usize;
fn count_disabled(&self) -> usize;
fn count_all(&self) -> usize;
fn is_empty(&self) -> bool {
self.count() == 0
}
fn add(&mut self, testcase: Testcase<I>) -> Result<CorpusId, Error>;
fn add_disabled(&mut self, testcase: Testcase<I>) -> Result<CorpusId, Error>;
fn replace(&mut self, id: CorpusId, testcase: Testcase<I>) -> Result<Testcase<I>, Error>;
fn remove(&mut self, id: CorpusId) -> Result<Testcase<I>, Error>;
fn get(&self, id: CorpusId) -> Result<&RefCell<Testcase<I>>, Error>;
fn get_from_all(&self, id: CorpusId) -> Result<&RefCell<Testcase<I>>, Error>;
fn current(&self) -> &Option<CorpusId>;
fn current_mut(&mut self) -> &mut Option<CorpusId>;
fn next(&self, id: CorpusId) -> Option<CorpusId>;
fn peek_free_id(&self) -> CorpusId;
fn prev(&self, id: CorpusId) -> Option<CorpusId>;
fn first(&self) -> Option<CorpusId>;
fn last(&self) -> Option<CorpusId>;
fn ids(&self) -> CorpusIdIterator<'_, Self, I> {
CorpusIdIterator {
corpus: self,
cur: self.first(),
cur_back: self.last(),
phantom: PhantomData,
}
}
fn nth(&self, nth: usize) -> CorpusId {
self.ids()
.nth(nth)
.unwrap_or_else(|| panic!("Failed to get the {nth} CorpusId"))
}
fn nth_from_all(&self, nth: usize) -> CorpusId;
fn load_input_into(&self, testcase: &mut Testcase<I>) -> Result<(), Error>;
fn store_input_from(&self, testcase: &Testcase<I>) -> Result<(), Error>;
fn cloned_input_for_id(&self, id: CorpusId) -> Result<I, Error>
where
I: Clone,
{
let mut testcase = self.get(id)?.borrow_mut();
Ok(testcase.load_input(self)?.clone())
}
}
pub trait EnableDisableCorpus {
fn disable(&mut self, id: CorpusId) -> Result<(), Error>;
fn enable(&mut self, id: CorpusId) -> Result<(), Error>;
}
pub trait HasCurrentCorpusId {
fn set_corpus_id(&mut self, id: CorpusId) -> Result<(), Error>;
fn clear_corpus_id(&mut self) -> Result<(), Error>;
fn current_corpus_id(&self) -> Result<Option<CorpusId>, Error>;
}
#[derive(Debug)]
pub struct CorpusIdIterator<'a, C, I> {
corpus: &'a C,
cur: Option<CorpusId>,
cur_back: Option<CorpusId>,
phantom: PhantomData<I>,
}
impl<C, I> Iterator for CorpusIdIterator<'_, C, I>
where
C: Corpus<I>,
{
type Item = CorpusId;
fn next(&mut self) -> Option<Self::Item> {
if let Some(cur) = self.cur {
self.cur = self.corpus.next(cur);
Some(cur)
} else {
None
}
}
}
impl<C, I> DoubleEndedIterator for CorpusIdIterator<'_, C, I>
where
C: Corpus<I>,
{
fn next_back(&mut self) -> Option<Self::Item> {
if let Some(cur_back) = self.cur_back {
self.cur_back = self.corpus.prev(cur_back);
Some(cur_back)
} else {
None
}
}
}