use std::fmt::Debug;
use crate::actions::Action;
use crate::deciders::LogicOperation;
use crate::error::FeroxFuzzError;
use crate::events::{EventPublisher, FuzzForever, FuzzNTimes};
use crate::state::SharedState;
use async_trait::async_trait;
use cfg_if::cfg_if;
use tracing::instrument;
cfg_if! {
if #[cfg(feature = "async")] {
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
mod async_fuzzer;
mod async_builder;
pub use async_builder::AsyncFuzzerBuilder;
pub use async_fuzzer::AsyncFuzzer;
}
}
cfg_if! {
if #[cfg(feature = "blocking")] {
#[cfg_attr(docsrs, doc(cfg(feature = "blocking")))]
mod blocking_fuzzer;
mod blocking_builder;
pub use blocking_builder::BlockingFuzzerBuilder;
pub use blocking_fuzzer::BlockingFuzzer;
}
}
pub trait Fuzzer {
fn pre_send_logic(&self) -> LogicOperation;
fn post_send_logic(&self) -> LogicOperation;
fn pre_send_logic_mut(&mut self) -> &mut LogicOperation;
fn post_send_logic_mut(&mut self) -> &mut LogicOperation;
fn reset(&mut self);
}
#[async_trait]
pub trait AsyncFuzzing: Fuzzer {
async fn fuzz(&mut self, state: &mut SharedState) -> Result<(), FeroxFuzzError> {
state.events().notify(FuzzForever);
loop {
if self.fuzz_once(state).await? == Some(Action::StopFuzzing) {
break Ok(());
}
self.reset();
}
}
async fn fuzz_once(
&mut self,
state: &mut SharedState,
) -> Result<Option<Action>, FeroxFuzzError>;
#[instrument(skip(self, state), level = "trace")]
async fn fuzz_n_iterations(
&mut self,
num_iterations: usize,
state: &mut SharedState,
) -> Result<(), FeroxFuzzError> {
state.events().notify(FuzzNTimes {
iterations: num_iterations,
});
for _ in 0..num_iterations {
if self.fuzz_once(state).await? == Some(Action::StopFuzzing) {
return Ok(());
}
self.reset();
}
Ok(())
}
}
pub trait BlockingFuzzing: Fuzzer {
fn fuzz(&mut self, state: &mut SharedState) -> Result<(), FeroxFuzzError> {
state.events().notify(FuzzForever);
loop {
if self.fuzz_once(state)? == Some(Action::StopFuzzing) {
break Ok(());
}
self.reset();
}
}
fn fuzz_once(&mut self, state: &mut SharedState) -> Result<Option<Action>, FeroxFuzzError>;
#[instrument(skip(self, state), level = "trace")]
fn fuzz_n_iterations(
&mut self,
num_iterations: usize,
state: &mut SharedState,
) -> Result<(), FeroxFuzzError> {
state.events().notify(FuzzNTimes {
iterations: num_iterations,
});
for _ in 0..num_iterations {
if self.fuzz_once(state)? == Some(Action::StopFuzzing) {
return Ok(());
}
self.reset();
}
Ok(())
}
}
#[derive(Clone)]
pub struct FuzzingLoopHook {
callback: fn(&mut SharedState),
called: usize,
}
impl FuzzingLoopHook {
pub fn new(callback: fn(&mut SharedState)) -> Self {
Self {
callback,
called: 0,
}
}
}
impl Debug for FuzzingLoopHook {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FuzzingLoopHook")
.field("called", &self.called)
.finish()
}
}
mod typestate {
pub trait FuzzerBuildState {}
pub struct NoClient;
pub struct NoRequest;
pub struct NoScheduler;
pub struct NoMutators;
pub struct NoObservers;
pub struct NoProcessors;
pub struct NoDeciders;
pub struct NoPreLoopHook;
pub struct NoPostLoopHook;
pub struct NoPreSendLogic;
pub struct NoPostSendLogic;
pub struct HasClient;
pub struct HasRequest;
pub struct HasScheduler;
pub struct HasMutators;
pub struct HasObservers;
pub struct HasProcessors;
pub struct HasDeciders;
pub struct HasPreLoopHook;
pub struct HasPostLoopHook;
pub struct HasPreSendLogic;
pub struct HasPostSendLogic;
impl FuzzerBuildState for NoClient {}
impl FuzzerBuildState for NoRequest {}
impl FuzzerBuildState for NoScheduler {}
impl FuzzerBuildState for NoMutators {}
impl FuzzerBuildState for NoObservers {}
impl FuzzerBuildState for NoProcessors {}
impl FuzzerBuildState for NoDeciders {}
impl FuzzerBuildState for NoPreLoopHook {}
impl FuzzerBuildState for NoPostLoopHook {}
impl FuzzerBuildState for NoPreSendLogic {}
impl FuzzerBuildState for NoPostSendLogic {}
impl FuzzerBuildState for HasClient {}
impl FuzzerBuildState for HasRequest {}
impl FuzzerBuildState for HasScheduler {}
impl FuzzerBuildState for HasMutators {}
impl FuzzerBuildState for HasObservers {}
impl FuzzerBuildState for HasProcessors {}
impl FuzzerBuildState for HasDeciders {}
impl FuzzerBuildState for HasPreLoopHook {}
impl FuzzerBuildState for HasPostLoopHook {}
impl FuzzerBuildState for HasPreSendLogic {}
impl FuzzerBuildState for HasPostSendLogic {}
}