use alloc::string::{String, ToString};
use std::{fmt::Debug, marker::PhantomData};
use hashbrown::HashSet;
use serde::{Deserialize, Serialize};
use crate::{
bolts::tuples::Named,
events::EventFirer,
executors::ExitKind,
feedbacks::{Feedback, HasObserverName},
inputs::UsesInput,
observers::{ObserverWithHashField, ObserversTuple},
state::{HasClientPerfMonitor, HasNamedMetadata},
Error,
};
pub const NEWHASHFEEDBACK_PREFIX: &str = "newhashfeedback_metadata_";
pub trait HashSetState<T> {
fn with_hash_set(hash_set: HashSet<T>) -> Self;
fn update_hash_set(&mut self, value: T) -> Result<bool, Error>;
}
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
pub struct NewHashFeedbackMetadata {
pub hash_set: HashSet<u64>,
}
#[rustfmt::skip]
crate::impl_serdeany!(NewHashFeedbackMetadata);
impl NewHashFeedbackMetadata {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn reset(&mut self) -> Result<(), Error> {
self.hash_set.clear();
Ok(())
}
}
impl HashSetState<u64> for NewHashFeedbackMetadata {
#[must_use]
fn with_hash_set(hash_set: HashSet<u64>) -> Self {
Self { hash_set }
}
fn update_hash_set(&mut self, value: u64) -> Result<bool, Error> {
let r = self.hash_set.insert(value);
Ok(r)
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct NewHashFeedback<O, S> {
name: String,
observer_name: String,
o_type: PhantomData<(O, S)>,
}
impl<O, S> Feedback<S> for NewHashFeedback<O, S>
where
O: ObserverWithHashField + Named + Debug,
S: UsesInput + Debug + HasNamedMetadata + HasClientPerfMonitor,
{
fn init_state(&mut self, state: &mut S) -> Result<(), Error> {
state.add_named_metadata(NewHashFeedbackMetadata::default(), &self.name);
Ok(())
}
#[allow(clippy::wrong_self_convention)]
fn is_interesting<EM, OT>(
&mut self,
state: &mut S,
_manager: &mut EM,
_input: &<S as UsesInput>::Input,
observers: &OT,
_exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
let observer = observers
.match_name::<O>(&self.observer_name)
.expect("A NewHashFeedback needs a BacktraceObserver");
let backtrace_state = state
.named_metadata_mut()
.get_mut::<NewHashFeedbackMetadata>(&self.name)
.unwrap();
match observer.hash() {
Some(hash) => {
let res = backtrace_state
.update_hash_set(hash)
.expect("Failed to update the hash state");
Ok(res)
}
None => {
Ok(false)
}
}
}
}
impl<O, S> Named for NewHashFeedback<O, S> {
#[inline]
fn name(&self) -> &str {
&self.name
}
}
impl<O, S> HasObserverName for NewHashFeedback<O, S> {
#[inline]
fn observer_name(&self) -> &str {
&self.observer_name
}
}
impl<O, S> NewHashFeedback<O, S>
where
O: ObserverWithHashField + Named + Debug,
{
#[must_use]
pub fn with_names(name: &str, observer_name: &str) -> Self {
Self {
name: name.to_string(),
observer_name: observer_name.to_string(),
o_type: PhantomData,
}
}
#[must_use]
pub fn new(observer: &O) -> Self {
Self {
name: NEWHASHFEEDBACK_PREFIX.to_string() + observer.name(),
observer_name: observer.name().to_string(),
o_type: PhantomData,
}
}
}