pub mod testcase;
pub use testcase::{SchedulerTestcaseMetaData, Testcase};
pub mod inmemory;
pub use inmemory::InMemoryCorpus;
#[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;
use core::{cell::RefCell, fmt};
#[cfg(feature = "cmin")]
pub use minimizer::*;
use serde::{Deserialize, Serialize};
use crate::{inputs::UsesInput, Error};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
#[repr(transparent)]
pub struct CorpusId(pub(crate) 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)
}
}
#[macro_export]
macro_rules! random_corpus_id {
($corpus:expr, $rand:expr) => {{
let cnt = $corpus.count() as u64;
let nth = $rand.below(cnt) as usize;
$corpus.nth(nth)
}};
}
pub trait Corpus: UsesInput + Serialize + for<'de> Deserialize<'de> {
fn count(&self) -> usize;
fn is_empty(&self) -> bool {
self.count() == 0
}
fn add(&mut self, testcase: Testcase<Self::Input>) -> Result<CorpusId, Error>;
fn replace(
&mut self,
idx: CorpusId,
testcase: Testcase<Self::Input>,
) -> Result<Testcase<Self::Input>, Error>;
fn remove(&mut self, id: CorpusId) -> Result<Testcase<Self::Input>, Error>;
fn get(&self, id: CorpusId) -> Result<&RefCell<Testcase<Self::Input>>, Error>;
fn current(&self) -> &Option<CorpusId>;
fn current_mut(&mut self) -> &mut Option<CorpusId>;
fn next(&self, id: CorpusId) -> Option<CorpusId>;
fn prev(&self, id: CorpusId) -> Option<CorpusId>;
fn first(&self) -> Option<CorpusId>;
fn last(&self) -> Option<CorpusId>;
fn ids(&self) -> CorpusIdIterator<'_, Self> {
CorpusIdIterator {
corpus: self,
cur: self.first(),
cur_back: self.last(),
}
}
fn nth(&self, nth: usize) -> CorpusId {
self.ids()
.nth(nth)
.expect("Failed to get the {nth} CorpusId")
}
}
#[derive(Debug)]
pub struct CorpusIdIterator<'a, C>
where
C: Corpus,
{
corpus: &'a C,
cur: Option<CorpusId>,
cur_back: Option<CorpusId>,
}
impl<'a, C> Iterator for CorpusIdIterator<'a, C>
where
C: Corpus,
{
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<'a, C> DoubleEndedIterator for CorpusIdIterator<'a, C>
where
C: Corpus,
{
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
}
}
}
#[cfg(feature = "python")]
#[allow(missing_docs)]
pub mod pybind {
use std::cell::RefCell;
use pyo3::prelude::*;
use serde::{Deserialize, Serialize};
use crate::{
corpus::{
cached::pybind::PythonCachedOnDiskCorpus, inmemory::pybind::PythonInMemoryCorpus,
ondisk::pybind::PythonOnDiskCorpus, testcase::pybind::PythonTestcaseWrapper, Corpus,
CorpusId, Testcase,
},
inputs::{BytesInput, UsesInput},
Error,
};
#[derive(Serialize, Deserialize, Debug, Clone)]
enum PythonCorpusWrapper {
InMemory(Py<PythonInMemoryCorpus>),
CachedOnDisk(Py<PythonCachedOnDiskCorpus>),
OnDisk(Py<PythonOnDiskCorpus>),
}
#[pyclass(unsendable, name = "Corpus")]
#[allow(clippy::unsafe_derive_deserialize)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct PythonCorpus {
wrapper: PythonCorpusWrapper,
}
macro_rules! unwrap_me {
($wrapper:expr, $name:ident, $body:block) => {
crate::unwrap_me_body!(
$wrapper,
$name,
$body,
PythonCorpusWrapper,
{
InMemory,
CachedOnDisk,
OnDisk
}
)
};
}
macro_rules! unwrap_me_mut {
($wrapper:expr, $name:ident, $body:block) => {
crate::unwrap_me_mut_body!(
$wrapper,
$name,
$body,
PythonCorpusWrapper,
{
InMemory,
CachedOnDisk,
OnDisk
}
)
};
}
#[pymethods]
impl PythonCorpus {
#[staticmethod]
#[must_use]
pub fn new_in_memory(py_in_memory_corpus: Py<PythonInMemoryCorpus>) -> Self {
Self {
wrapper: PythonCorpusWrapper::InMemory(py_in_memory_corpus),
}
}
#[staticmethod]
#[must_use]
pub fn new_cached_on_disk(py_cached_on_disk_corpus: Py<PythonCachedOnDiskCorpus>) -> Self {
Self {
wrapper: PythonCorpusWrapper::CachedOnDisk(py_cached_on_disk_corpus),
}
}
#[staticmethod]
#[must_use]
pub fn new_on_disk(py_on_disk_corpus: Py<PythonOnDiskCorpus>) -> Self {
Self {
wrapper: PythonCorpusWrapper::OnDisk(py_on_disk_corpus),
}
}
#[pyo3(name = "count")]
fn pycount(&self) -> usize {
self.count()
}
#[pyo3(name = "current")]
fn pycurrent(&self) -> Option<usize> {
self.current().map(|x| x.0)
}
#[pyo3(name = "get")]
fn pyget(&self, idx: usize) -> PythonTestcaseWrapper {
let t: &mut Testcase<BytesInput> = unwrap_me!(self.wrapper, c, {
c.get(CorpusId::from(idx))
.map(|v| unsafe { v.as_ptr().as_mut().unwrap() })
.expect("PythonCorpus::get failed")
});
PythonTestcaseWrapper::wrap(t)
}
}
impl UsesInput for PythonCorpus {
type Input = BytesInput;
}
impl Corpus for PythonCorpus {
#[inline]
fn count(&self) -> usize {
unwrap_me!(self.wrapper, c, { c.count() })
}
#[inline]
fn add(&mut self, testcase: Testcase<BytesInput>) -> Result<CorpusId, Error> {
unwrap_me_mut!(self.wrapper, c, { c.add(testcase) })
}
#[inline]
fn replace(
&mut self,
idx: CorpusId,
testcase: Testcase<BytesInput>,
) -> Result<Testcase<BytesInput>, Error> {
unwrap_me_mut!(self.wrapper, c, { c.replace(idx, testcase) })
}
#[inline]
fn remove(&mut self, idx: CorpusId) -> Result<Testcase<BytesInput>, Error> {
unwrap_me_mut!(self.wrapper, c, { c.remove(idx) })
}
#[inline]
fn get(&self, idx: CorpusId) -> Result<&RefCell<Testcase<BytesInput>>, Error> {
let ptr = unwrap_me!(self.wrapper, c, {
c.get(idx)
.map(|v| v as *const RefCell<Testcase<BytesInput>>)
})?;
Ok(unsafe { ptr.as_ref().unwrap() })
}
#[inline]
fn current(&self) -> &Option<CorpusId> {
let ptr = unwrap_me!(self.wrapper, c, { c.current() as *const Option<CorpusId> });
unsafe { ptr.as_ref().unwrap() }
}
#[inline]
fn current_mut(&mut self) -> &mut Option<CorpusId> {
let ptr = unwrap_me_mut!(self.wrapper, c, {
c.current_mut() as *mut Option<CorpusId>
});
unsafe { ptr.as_mut().unwrap() }
}
fn next(&self, idx: CorpusId) -> Option<CorpusId> {
unwrap_me!(self.wrapper, c, { c.next(idx) })
}
fn prev(&self, idx: CorpusId) -> Option<CorpusId> {
unwrap_me!(self.wrapper, c, { c.prev(idx) })
}
fn first(&self) -> Option<CorpusId> {
unwrap_me!(self.wrapper, c, { c.first() })
}
fn last(&self) -> Option<CorpusId> {
unwrap_me!(self.wrapper, c, { c.last() })
}
}
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonCorpus>()?;
Ok(())
}
}