State is now a struct
This commit is contained in:
parent
ff983ecf23
commit
de4fb23f31
@ -19,167 +19,12 @@ use crate::stages::Stage;
|
|||||||
use crate::utils::{current_milliseconds, Rand};
|
use crate::utils::{current_milliseconds, Rand};
|
||||||
use crate::AflError;
|
use crate::AflError;
|
||||||
|
|
||||||
// TODO FeedbackMetadata to store histroy_map
|
|
||||||
|
|
||||||
pub trait StateMetadata: Debug {
|
pub trait StateMetadata: Debug {
|
||||||
/// The name of this metadata - used to find it in the list of avaliable metadatas
|
/// The name of this metadata - used to find it in the list of avaliable metadatas
|
||||||
fn name(&self) -> &'static str;
|
fn name(&self) -> &'static str;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait State<C, E, I, R>
|
pub struct State<C, E, I, R>
|
||||||
where
|
|
||||||
C: Corpus<I, R>,
|
|
||||||
E: Executor<I>,
|
|
||||||
I: Input,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
/// Get executions
|
|
||||||
fn executions(&self) -> usize;
|
|
||||||
|
|
||||||
/// Set executions
|
|
||||||
fn set_executions(&mut self, executions: usize);
|
|
||||||
|
|
||||||
fn start_time(&self) -> u64;
|
|
||||||
fn set_start_time(&mut self, ms: u64);
|
|
||||||
|
|
||||||
fn executions_over_seconds(&self) -> u64 {
|
|
||||||
let elapsed = current_milliseconds() - self.start_time();
|
|
||||||
if elapsed == 0 {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
let elapsed = elapsed / 1000;
|
|
||||||
if elapsed == 0 {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
(self.executions() as u64) / elapsed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get all the metadatas into an HashMap
|
|
||||||
fn metadatas(&self) -> &HashMap<&'static str, Box<dyn StateMetadata>>;
|
|
||||||
|
|
||||||
/// Get all the metadatas into an HashMap (mutable)
|
|
||||||
fn metadatas_mut(&mut self) -> &mut HashMap<&'static str, Box<dyn StateMetadata>>;
|
|
||||||
|
|
||||||
/// Add a metadata
|
|
||||||
fn add_metadata(&mut self, meta: Box<dyn StateMetadata>) {
|
|
||||||
self.metadatas_mut().insert(meta.name(), meta);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns vector of feebacks
|
|
||||||
fn feedbacks(&self) -> &[Box<dyn Feedback<I>>];
|
|
||||||
|
|
||||||
/// Returns vector of feebacks (mutable)
|
|
||||||
fn feedbacks_mut(&mut self) -> &mut Vec<Box<dyn Feedback<I>>>;
|
|
||||||
|
|
||||||
/// Adds a feedback
|
|
||||||
fn add_feedback(&mut self, feedback: Box<dyn Feedback<I>>) {
|
|
||||||
self.feedbacks_mut().push(feedback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the executor
|
|
||||||
fn executor(&self) -> &E;
|
|
||||||
|
|
||||||
/// Return the executor (mutable)
|
|
||||||
fn executor_mut(&mut self) -> &mut E;
|
|
||||||
|
|
||||||
/// Runs the input and triggers observers and feedback
|
|
||||||
fn evaluate_input(&mut self, input: &I) -> Result<u32, AflError> {
|
|
||||||
self.executor_mut().reset_observers()?;
|
|
||||||
self.executor_mut().run_target(&input)?;
|
|
||||||
self.set_executions(self.executions() + 1);
|
|
||||||
self.executor_mut().post_exec_observers()?;
|
|
||||||
|
|
||||||
let mut fitness = 0;
|
|
||||||
let observers = self.executor().observers();
|
|
||||||
for feedback in self.feedbacks_mut() {
|
|
||||||
fitness += feedback.is_interesting(&input, observers)?;
|
|
||||||
}
|
|
||||||
Ok(fitness)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Resets all current feedbacks
|
|
||||||
fn discard_input(&mut self, input: &I) -> Result<(), AflError> {
|
|
||||||
// TODO: This could probably be automatic in the feedback somehow?
|
|
||||||
for feedback in self.feedbacks_mut() {
|
|
||||||
feedback.discard_metadata(input)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new testcase, appending the metadata from each feedback
|
|
||||||
fn input_to_testcase(&mut self, input: I, fitness: u32) -> Result<Testcase<I>, AflError> {
|
|
||||||
let mut testcase = Testcase::new(input);
|
|
||||||
testcase.set_fitness(fitness);
|
|
||||||
for feedback in self.feedbacks_mut() {
|
|
||||||
feedback.append_metadata(&mut testcase)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(testcase)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a testcase from this input, if it's intersting
|
|
||||||
fn testcase_if_interesting(
|
|
||||||
&mut self,
|
|
||||||
input: I,
|
|
||||||
fitness: u32,
|
|
||||||
) -> Result<Option<Testcase<I>>, AflError> {
|
|
||||||
if fitness > 0 {
|
|
||||||
Ok(Some(self.input_to_testcase(input, fitness)?))
|
|
||||||
} else {
|
|
||||||
self.discard_input(&input)?;
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds this input to the corpus, if it's intersting
|
|
||||||
fn add_if_interesting(
|
|
||||||
&mut self,
|
|
||||||
corpus: &mut C,
|
|
||||||
input: I,
|
|
||||||
fitness: u32,
|
|
||||||
) -> Result<Option<usize>, AflError> {
|
|
||||||
if fitness > 0 {
|
|
||||||
let testcase = self.input_to_testcase(input, fitness)?;
|
|
||||||
Ok(Some(corpus.add(testcase)))
|
|
||||||
} else {
|
|
||||||
self.discard_input(&input)?;
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generate_initial_inputs<S, G, C, E, I, R, EM>(
|
|
||||||
rand: &mut R,
|
|
||||||
state: &mut S,
|
|
||||||
corpus: &mut C,
|
|
||||||
generator: &mut G,
|
|
||||||
events: &mut EM,
|
|
||||||
num: usize,
|
|
||||||
) -> Result<(), AflError>
|
|
||||||
where
|
|
||||||
S: State<C, E, I, R>,
|
|
||||||
G: Generator<I, R>,
|
|
||||||
C: Corpus<I, R>,
|
|
||||||
E: Executor<I>,
|
|
||||||
I: Input,
|
|
||||||
R: Rand,
|
|
||||||
EM: EventManager<S, C, E, I, R>,
|
|
||||||
{
|
|
||||||
for _ in 0..num {
|
|
||||||
let input = generator.generate(rand)?;
|
|
||||||
let fitness = state.evaluate_input(&input)?;
|
|
||||||
state.add_if_interesting(corpus, input, fitness)?;
|
|
||||||
events.fire(Event::LoadInitial {
|
|
||||||
sender_id: 0,
|
|
||||||
phantom: PhantomData,
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
events.process(state, corpus)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct StdState<C, E, I, R>
|
|
||||||
where
|
where
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I, R>,
|
||||||
E: Executor<I>,
|
E: Executor<I>,
|
||||||
@ -196,60 +41,167 @@ where
|
|||||||
phantom: PhantomData<(C, R)>,
|
phantom: PhantomData<(C, R)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, E, I, R> State<C, E, I, R> for StdState<C, E, I, R>
|
impl<C, E, I, R> State<C, E, I, R>
|
||||||
where
|
where
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I, R>,
|
||||||
E: Executor<I>,
|
E: Executor<I>,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
fn executions(&self) -> usize {
|
/// Get executions
|
||||||
|
pub fn executions(&self) -> usize {
|
||||||
self.executions
|
self.executions
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_executions(&mut self, executions: usize) {
|
/// Set executions
|
||||||
|
pub fn set_executions(&mut self, executions: usize){
|
||||||
self.executions = executions
|
self.executions = executions
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_time(&self) -> u64 {
|
pub fn start_time(&self) -> u64{
|
||||||
self.start_time
|
self.start_time
|
||||||
}
|
}
|
||||||
fn set_start_time(&mut self, ms: u64) {
|
pub fn set_start_time(&mut self, ms: u64) {
|
||||||
self.start_time = ms
|
self.start_time = ms
|
||||||
}
|
}
|
||||||
|
|
||||||
fn metadatas(&self) -> &HashMap<&'static str, Box<dyn StateMetadata>> {
|
pub fn executions_over_seconds(&self) -> u64 {
|
||||||
|
let elapsed = current_milliseconds() - self.start_time();
|
||||||
|
if elapsed == 0 {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
let elapsed = elapsed / 1000;
|
||||||
|
if elapsed == 0 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
(self.executions() as u64) / elapsed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get all the metadatas into an HashMap
|
||||||
|
pub fn metadatas(&self) -> &HashMap<&'static str, Box<dyn StateMetadata>>{
|
||||||
&self.metadatas
|
&self.metadatas
|
||||||
}
|
}
|
||||||
|
|
||||||
fn metadatas_mut(&mut self) -> &mut HashMap<&'static str, Box<dyn StateMetadata>> {
|
/// Get all the metadatas into an HashMap (mutable)
|
||||||
|
pub fn metadatas_mut(&mut self) -> &mut HashMap<&'static str, Box<dyn StateMetadata>>{
|
||||||
&mut self.metadatas
|
&mut self.metadatas
|
||||||
}
|
}
|
||||||
|
|
||||||
fn feedbacks(&self) -> &[Box<dyn Feedback<I>>] {
|
/// Add a metadata
|
||||||
|
pub fn add_metadata(&mut self, meta: Box<dyn StateMetadata>) {
|
||||||
|
self.metadatas_mut().insert(meta.name(), meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns vector of feebacks
|
||||||
|
pub fn feedbacks(&self) -> &[Box<dyn Feedback<I>>]{
|
||||||
&self.feedbacks
|
&self.feedbacks
|
||||||
}
|
}
|
||||||
|
|
||||||
fn feedbacks_mut(&mut self) -> &mut Vec<Box<dyn Feedback<I>>> {
|
/// Returns vector of feebacks (mutable)
|
||||||
|
pub fn feedbacks_mut(&mut self) -> &mut Vec<Box<dyn Feedback<I>>>{
|
||||||
&mut self.feedbacks
|
&mut self.feedbacks
|
||||||
}
|
}
|
||||||
|
|
||||||
fn executor(&self) -> &E {
|
/// Adds a feedback
|
||||||
&self.executor
|
pub fn add_feedback(&mut self, feedback: Box<dyn Feedback<I>>) {
|
||||||
|
self.feedbacks_mut().push(feedback);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn executor_mut(&mut self) -> &mut E {
|
/// Runs the input and triggers observers and feedback
|
||||||
&mut self.executor
|
pub fn evaluate_input<FE, EM>(&mut self, input: &I, engine: &FE) -> Result<u32, AflError>
|
||||||
}
|
where
|
||||||
}
|
FE: FuzzingEngine<EM, E, C, I, R>,
|
||||||
|
EM: EventManager<C, E, I, R>,
|
||||||
|
{
|
||||||
|
engine.executor_mut().reset_observers()?;
|
||||||
|
engine.executor_mut().run_target(&input)?;
|
||||||
|
self.set_executions(self.executions() + 1);
|
||||||
|
engine.executor_mut().post_exec_observers()?;
|
||||||
|
|
||||||
|
let mut fitness = 0;
|
||||||
|
let observers = self.executor().observers();
|
||||||
|
for feedback in self.feedbacks_mut() {
|
||||||
|
fitness += feedback.is_interesting(&input, observers)?;
|
||||||
|
}
|
||||||
|
Ok(fitness)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resets all current feedbacks
|
||||||
|
pub fn discard_input(&mut self, input: &I) -> Result<(), AflError> {
|
||||||
|
// TODO: This could probably be automatic in the feedback somehow?
|
||||||
|
for feedback in self.feedbacks_mut() {
|
||||||
|
feedback.discard_metadata(input)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new testcase, appending the metadata from each feedback
|
||||||
|
pub fn input_to_testcase(&mut self, input: I, fitness: u32) -> Result<Testcase<I>, AflError> {
|
||||||
|
let mut testcase = Testcase::new(input);
|
||||||
|
testcase.set_fitness(fitness);
|
||||||
|
for feedback in self.feedbacks_mut() {
|
||||||
|
feedback.append_metadata(&mut testcase)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(testcase)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a testcase from this input, if it's intersting
|
||||||
|
pub fn testcase_if_interesting(
|
||||||
|
&mut self,
|
||||||
|
input: I,
|
||||||
|
fitness: u32,
|
||||||
|
) -> Result<Option<Testcase<I>>, AflError> {
|
||||||
|
if fitness > 0 {
|
||||||
|
Ok(Some(self.input_to_testcase(input, fitness)?))
|
||||||
|
} else {
|
||||||
|
self.discard_input(&input)?;
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds this input to the corpus, if it's intersting
|
||||||
|
pub fn add_if_interesting(
|
||||||
|
&mut self,
|
||||||
|
corpus: &mut C,
|
||||||
|
input: I,
|
||||||
|
fitness: u32,
|
||||||
|
) -> Result<Option<usize>, AflError> {
|
||||||
|
if fitness > 0 {
|
||||||
|
let testcase = self.input_to_testcase(input, fitness)?;
|
||||||
|
Ok(Some(corpus.add(testcase)))
|
||||||
|
} else {
|
||||||
|
self.discard_input(&input)?;
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_initial_inputs<G, EM>(
|
||||||
|
&mut self,
|
||||||
|
rand: &mut R,
|
||||||
|
corpus: &mut C,
|
||||||
|
generator: &mut G,
|
||||||
|
events: &mut EM,
|
||||||
|
num: usize,
|
||||||
|
) -> Result<(), AflError>
|
||||||
|
where
|
||||||
|
G: Generator<I, R>,
|
||||||
|
EM: EventManager<C, E, I, R>,
|
||||||
|
{
|
||||||
|
for _ in 0..num {
|
||||||
|
let input = generator.generate(rand)?;
|
||||||
|
let fitness = self.evaluate_input(&input)?;
|
||||||
|
self.add_if_interesting(corpus, input, fitness)?;
|
||||||
|
events.fire(Event::LoadInitial {
|
||||||
|
sender_id: 0,
|
||||||
|
phantom: PhantomData,
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
events.process(self, corpus)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
impl<C, E, I, R> StdState<C, E, I, R>
|
|
||||||
where
|
|
||||||
C: Corpus<I, R>,
|
|
||||||
E: Executor<I>,
|
|
||||||
I: Input,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
pub fn new(executor: E) -> Self {
|
pub fn new(executor: E) -> Self {
|
||||||
Self {
|
Self {
|
||||||
executions: 0,
|
executions: 0,
|
||||||
@ -263,27 +215,38 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Engine<S, EM, E, C, I, R>
|
pub trait FuzzingEngine<EM, E, C, I, R>
|
||||||
where
|
where
|
||||||
S: State<C, E, I, R>,
|
EM: EventManager<C, E, I, R>,
|
||||||
EM: EventManager<S, C, E, I, R>,
|
|
||||||
E: Executor<I>,
|
E: Executor<I>,
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
fn stages(&self) -> &[Box<dyn Stage<S, EM, E, C, I, R>>];
|
fn stages(&self) -> &[Box<dyn Stage<EM, E, C, I, R>>];
|
||||||
|
|
||||||
fn stages_mut(&mut self) -> &mut Vec<Box<dyn Stage<S, EM, E, C, I, R>>>;
|
fn stages_mut(&mut self) -> &mut Vec<Box<dyn Stage<EM, E, C, I, R>>>;
|
||||||
|
|
||||||
fn add_stage(&mut self, stage: Box<dyn Stage<S, EM, E, C, I, R>>) {
|
fn add_stage(&mut self, stage: Box<dyn Stage<EM, E, C, I, R>>) {
|
||||||
self.stages_mut().push(stage);
|
self.stages_mut().push(stage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn events_manager(&self) -> &EM;
|
||||||
|
|
||||||
|
fn events_manager_mut(&mut self) -> &mut EM;
|
||||||
|
|
||||||
|
/// Return the executor
|
||||||
|
fn executor(&self) -> &E;
|
||||||
|
|
||||||
|
/// Return the executor (mutable)
|
||||||
|
fn executor_mut(&mut self) -> &mut E;
|
||||||
|
|
||||||
|
// TODO additional executors, Vec<Box<dyn Executor<I>>>
|
||||||
|
|
||||||
fn fuzz_one(
|
fn fuzz_one(
|
||||||
&mut self,
|
&mut self,
|
||||||
rand: &mut R,
|
rand: &mut R,
|
||||||
state: &mut S,
|
state: &mut State<C, E, I, R>,
|
||||||
corpus: &mut C,
|
corpus: &mut C,
|
||||||
events: &mut EM,
|
events: &mut EM,
|
||||||
) -> Result<usize, AflError> {
|
) -> Result<usize, AflError> {
|
||||||
@ -309,7 +272,7 @@ where
|
|||||||
fn fuzz_loop(
|
fn fuzz_loop(
|
||||||
&mut self,
|
&mut self,
|
||||||
rand: &mut R,
|
rand: &mut R,
|
||||||
state: &mut S,
|
state: &mut State<C, E, I, R>,
|
||||||
corpus: &mut C,
|
corpus: &mut C,
|
||||||
events: &mut EM,
|
events: &mut EM,
|
||||||
) -> Result<(), AflError> {
|
) -> Result<(), AflError> {
|
||||||
@ -329,41 +292,38 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct StdEngine<S, EM, E, C, I, R>
|
pub struct StdFuzzingEngine<EM, E, C, I, R>
|
||||||
where
|
where
|
||||||
S: State<C, E, I, R>,
|
EM: EventManager<C, E, I, R>,
|
||||||
EM: EventManager<S, C, E, I, R>,
|
|
||||||
E: Executor<I>,
|
E: Executor<I>,
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
stages: Vec<Box<dyn Stage<S, EM, E, C, I, R>>>,
|
stages: Vec<Box<dyn Stage<EM, E, C, I, R>>>,
|
||||||
phantom: PhantomData<EM>,
|
phantom: PhantomData<EM>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, EM, E, C, I, R> Engine<S, EM, E, C, I, R> for StdEngine<S, EM, E, C, I, R>
|
impl<EM, E, C, I, R> FuzzingEngine<EM, E, C, I, R> for StdFuzzingEngine<EM, E, C, I, R>
|
||||||
where
|
where
|
||||||
S: State<C, E, I, R>,
|
EM: EventManager<C, E, I, R>,
|
||||||
EM: EventManager<S, C, E, I, R>,
|
|
||||||
E: Executor<I>,
|
E: Executor<I>,
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
fn stages(&self) -> &[Box<dyn Stage<S, EM, E, C, I, R>>] {
|
fn stages(&self) -> &[Box<dyn Stage<EM, E, C, I, R>>] {
|
||||||
&self.stages
|
&self.stages
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stages_mut(&mut self) -> &mut Vec<Box<dyn Stage<S, EM, E, C, I, R>>> {
|
fn stages_mut(&mut self) -> &mut Vec<Box<dyn Stage<EM, E, C, I, R>>> {
|
||||||
&mut self.stages
|
&mut self.stages
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, EM, E, C, I, R> StdEngine<S, EM, E, C, I, R>
|
impl<EM, E, C, I, R> StdFuzzingEngine<EM, E, C, I, R>
|
||||||
where
|
where
|
||||||
S: State<C, E, I, R>,
|
EM: EventManager<C, E, I, R>,
|
||||||
EM: EventManager<S, C, E, I, R>,
|
|
||||||
E: Executor<I>,
|
E: Executor<I>,
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
@ -9,10 +9,9 @@ use crate::inputs::Input;
|
|||||||
use crate::utils::Rand;
|
use crate::utils::Rand;
|
||||||
use crate::AflError;
|
use crate::AflError;
|
||||||
|
|
||||||
pub trait Stage<S, EM, E, C, I, R>
|
pub trait Stage<EM, E, C, I, R>
|
||||||
where
|
where
|
||||||
S: State<C, E, I, R>,
|
EM: EventManager<C, E, I, R>,
|
||||||
EM: EventManager<S, C, E, I, R>,
|
|
||||||
E: Executor<I>,
|
E: Executor<I>,
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
@ -22,7 +21,7 @@ where
|
|||||||
fn perform(
|
fn perform(
|
||||||
&mut self,
|
&mut self,
|
||||||
rand: &mut R,
|
rand: &mut R,
|
||||||
state: &mut S,
|
state: &mut State<C, E, I, R>,
|
||||||
corpus: &C,
|
corpus: &C,
|
||||||
events: &mut EM,
|
events: &mut EM,
|
||||||
input: &I,
|
input: &I,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user