pub mod map;
pub use map::*;
use alloc::string::{String, ToString};
use serde::{Deserialize, Serialize};
use crate::{
bolts::tuples::Named,
corpus::Testcase,
executors::ExitKind,
inputs::Input,
observers::{ObserversTuple, TimeObserver},
Error,
};
use core::{marker::PhantomData, time::Duration};
pub trait Feedback<I>: Named + serde::Serialize + serde::de::DeserializeOwned
where
I: Input,
{
fn is_interesting<OT>(
&mut self,
input: &I,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
OT: ObserversTuple;
#[inline]
fn append_metadata(&mut self, _testcase: &mut Testcase<I>) -> Result<(), Error> {
Ok(())
}
#[inline]
fn discard_metadata(&mut self, _input: &I) -> Result<(), Error> {
Ok(())
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "I: serde::de::DeserializeOwned")]
pub struct AndFeedback<A, B, I>
where
A: Feedback<I>,
B: Feedback<I>,
I: Input,
{
pub first: A,
pub second: B,
phantom: PhantomData<I>,
}
impl<A, B, I> Feedback<I> for AndFeedback<A, B, I>
where
A: Feedback<I>,
B: Feedback<I>,
I: Input,
{
fn is_interesting<OT>(
&mut self,
input: &I,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
OT: ObserversTuple,
{
let a = self.first.is_interesting(input, observers, exit_kind)?;
let b = self.second.is_interesting(input, observers, exit_kind)?;
Ok(a && b)
}
#[inline]
fn append_metadata(&mut self, testcase: &mut Testcase<I>) -> Result<(), Error> {
self.first.append_metadata(testcase)?;
self.second.append_metadata(testcase)
}
#[inline]
fn discard_metadata(&mut self, input: &I) -> Result<(), Error> {
self.first.discard_metadata(input)?;
self.second.discard_metadata(input)
}
}
impl<A, B, I> Named for AndFeedback<A, B, I>
where
A: Feedback<I>,
B: Feedback<I>,
I: Input,
{
#[inline]
fn name(&self) -> &str {
"AndFeedback"
}
}
impl<A, B, I> AndFeedback<A, B, I>
where
A: Feedback<I>,
B: Feedback<I>,
I: Input,
{
pub fn new(first: A, second: B) -> Self {
Self {
first,
second,
phantom: PhantomData,
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "I: serde::de::DeserializeOwned")]
pub struct OrFeedback<A, B, I>
where
A: Feedback<I>,
B: Feedback<I>,
I: Input,
{
pub first: A,
pub second: B,
phantom: PhantomData<I>,
}
impl<A, B, I> Feedback<I> for OrFeedback<A, B, I>
where
A: Feedback<I>,
B: Feedback<I>,
I: Input,
{
fn is_interesting<OT>(
&mut self,
input: &I,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
OT: ObserversTuple,
{
let a = self.first.is_interesting(input, observers, exit_kind)?;
let b = self.second.is_interesting(input, observers, exit_kind)?;
Ok(a || b)
}
#[inline]
fn append_metadata(&mut self, testcase: &mut Testcase<I>) -> Result<(), Error> {
self.first.append_metadata(testcase)?;
self.second.append_metadata(testcase)
}
#[inline]
fn discard_metadata(&mut self, input: &I) -> Result<(), Error> {
self.first.discard_metadata(input)?;
self.second.discard_metadata(input)
}
}
impl<A, B, I> Named for OrFeedback<A, B, I>
where
A: Feedback<I>,
B: Feedback<I>,
I: Input,
{
#[inline]
fn name(&self) -> &str {
"OrFeedback"
}
}
impl<A, B, I> OrFeedback<A, B, I>
where
A: Feedback<I>,
B: Feedback<I>,
I: Input,
{
pub fn new(first: A, second: B) -> Self {
Self {
first,
second,
phantom: PhantomData,
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "I: serde::de::DeserializeOwned")]
pub struct NotFeedback<A, I>
where
A: Feedback<I>,
I: Input,
{
pub first: A,
phantom: PhantomData<I>,
}
impl<A, I> Feedback<I> for NotFeedback<A, I>
where
A: Feedback<I>,
I: Input,
{
fn is_interesting<OT>(
&mut self,
input: &I,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
OT: ObserversTuple,
{
Ok(!self.first.is_interesting(input, observers, exit_kind)?)
}
#[inline]
fn append_metadata(&mut self, testcase: &mut Testcase<I>) -> Result<(), Error> {
self.first.append_metadata(testcase)
}
#[inline]
fn discard_metadata(&mut self, input: &I) -> Result<(), Error> {
self.first.discard_metadata(input)
}
}
impl<A, I> Named for NotFeedback<A, I>
where
A: Feedback<I>,
I: Input,
{
#[inline]
fn name(&self) -> &str {
"NotFeedback"
}
}
impl<A, I> NotFeedback<A, I>
where
A: Feedback<I>,
I: Input,
{
pub fn new(first: A) -> Self {
Self {
first,
phantom: PhantomData,
}
}
}
#[macro_export]
macro_rules! feedback_and {
( $last:expr ) => { $last };
( $head:expr, $($tail:expr), +) => {
$crate::feedbacks::AndFeedback::new($head , feedback_and!($($tail),+))
};
}
#[macro_export]
macro_rules! feedback_or {
( $last:expr ) => { $last };
( $head:expr, $($tail:expr), +) => {
$crate::feedbacks::OrFeedback::new($head , feedback_or!($($tail),+))
};
}
#[macro_export]
macro_rules! feedback_not {
( $last:expr ) => {
$crate::feedbacks::NotFeedback::new($last)
};
}
impl<I> Feedback<I> for ()
where
I: Input,
{
fn is_interesting<OT>(
&mut self,
_input: &I,
_observers: &OT,
_exit_kind: &ExitKind,
) -> Result<bool, Error>
where
OT: ObserversTuple,
{
Ok(false)
}
}
impl Named for () {
#[inline]
fn name(&self) -> &str {
"Empty"
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct CrashFeedback {}
impl<I> Feedback<I> for CrashFeedback
where
I: Input,
{
fn is_interesting<OT>(
&mut self,
_input: &I,
_observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
OT: ObserversTuple,
{
if let ExitKind::Crash = exit_kind {
Ok(true)
} else {
Ok(false)
}
}
}
impl Named for CrashFeedback {
#[inline]
fn name(&self) -> &str {
"CrashFeedback"
}
}
impl CrashFeedback {
#[must_use]
pub fn new() -> Self {
Self {}
}
}
impl Default for CrashFeedback {
fn default() -> Self {
Self::new()
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct TimeoutFeedback {}
impl<I> Feedback<I> for TimeoutFeedback
where
I: Input,
{
fn is_interesting<OT>(
&mut self,
_input: &I,
_observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
OT: ObserversTuple,
{
if let ExitKind::Timeout = exit_kind {
Ok(true)
} else {
Ok(false)
}
}
}
impl Named for TimeoutFeedback {
#[inline]
fn name(&self) -> &str {
"TimeoutFeedback"
}
}
impl TimeoutFeedback {
#[must_use]
pub fn new() -> Self {
Self {}
}
}
impl Default for TimeoutFeedback {
fn default() -> Self {
Self::new()
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct TimeFeedback {
exec_time: Option<Duration>,
name: String,
}
impl<I> Feedback<I> for TimeFeedback
where
I: Input,
{
fn is_interesting<OT>(
&mut self,
_input: &I,
observers: &OT,
_exit_kind: &ExitKind,
) -> Result<bool, Error>
where
OT: ObserversTuple,
{
let observer = observers.match_name::<TimeObserver>(self.name()).unwrap();
self.exec_time = *observer.last_runtime();
Ok(false)
}
#[inline]
fn append_metadata(&mut self, testcase: &mut Testcase<I>) -> Result<(), Error> {
*testcase.exec_time_mut() = self.exec_time;
self.exec_time = None;
Ok(())
}
#[inline]
fn discard_metadata(&mut self, _input: &I) -> Result<(), Error> {
self.exec_time = None;
Ok(())
}
}
impl Named for TimeFeedback {
#[inline]
fn name(&self) -> &str {
self.name.as_str()
}
}
impl TimeFeedback {
#[must_use]
pub fn new(name: &'static str) -> Self {
Self {
exec_time: None,
name: name.to_string(),
}
}
#[must_use]
pub fn new_with_observer(observer: &TimeObserver) -> Self {
Self {
exec_time: None,
name: observer.name().to_string(),
}
}
}