Add HitcountsIterableMapObserver, rename AsMutIter to AsIterMut (#713)
* Move HitcountsMapObserver back to iterators to make it usable with cargo-libafl * clippy * optimize the good-case * safety info added * mut_iter -> iter_mut * split up map observer
This commit is contained in:
parent
a5248d0250
commit
8d5699a335
@ -47,25 +47,25 @@ pub trait AsMutSlice<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create an `Iterator` from a reference
|
/// Create an `Iterator` from a reference
|
||||||
pub trait AsRefIterator<'it> {
|
pub trait AsIter<'it> {
|
||||||
/// The item type
|
/// The item type
|
||||||
type Item: 'it;
|
type Item: 'it;
|
||||||
/// The iterator type
|
/// The iterator type
|
||||||
type IntoIter: Iterator<Item = &'it Self::Item>;
|
type IntoIter: Iterator<Item = &'it Self::Item>;
|
||||||
|
|
||||||
/// Create an interator from &self
|
/// Create an interator from &self
|
||||||
fn as_ref_iter(&'it self) -> Self::IntoIter;
|
fn as_iter(&'it self) -> Self::IntoIter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create an `Iterator` from a mutable reference
|
/// Create an `Iterator` from a mutable reference
|
||||||
pub trait AsMutIterator<'it> {
|
pub trait AsIterMut<'it> {
|
||||||
/// The item type
|
/// The item type
|
||||||
type Item: 'it;
|
type Item: 'it;
|
||||||
/// The iterator type
|
/// The iterator type
|
||||||
type IntoIter: Iterator<Item = &'it mut Self::Item>;
|
type IntoIter: Iterator<Item = &'it mut Self::Item>;
|
||||||
|
|
||||||
/// Create an interator from &mut self
|
/// Create an interator from &mut self
|
||||||
fn as_mut_iter(&'it mut self) -> Self::IntoIter;
|
fn as_iter_mut(&'it mut self) -> Self::IntoIter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Has a length field
|
/// Has a length field
|
||||||
|
@ -10,7 +10,7 @@ use num_traits::PrimInt;
|
|||||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::{tuples::Named, AsMutSlice, AsRefIterator, AsSlice, HasRefCnt},
|
bolts::{tuples::Named, AsIter, AsMutSlice, AsSlice, HasRefCnt},
|
||||||
corpus::Testcase,
|
corpus::Testcase,
|
||||||
events::{Event, EventFirer},
|
events::{Event, EventFirer},
|
||||||
executors::ExitKind,
|
executors::ExitKind,
|
||||||
@ -323,7 +323,7 @@ where
|
|||||||
T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug,
|
T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug,
|
||||||
R: Reducer<T>,
|
R: Reducer<T>,
|
||||||
O: MapObserver<Entry = T>,
|
O: MapObserver<Entry = T>,
|
||||||
for<'it> O: AsRefIterator<'it, Item = T>,
|
for<'it> O: AsIter<'it, Item = T>,
|
||||||
N: IsNovel<T>,
|
N: IsNovel<T>,
|
||||||
S: HasNamedMetadata,
|
S: HasNamedMetadata,
|
||||||
{
|
{
|
||||||
@ -346,7 +346,7 @@ where
|
|||||||
T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug,
|
T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug,
|
||||||
R: Reducer<T>,
|
R: Reducer<T>,
|
||||||
O: MapObserver<Entry = T>,
|
O: MapObserver<Entry = T>,
|
||||||
for<'it> O: AsRefIterator<'it, Item = T>,
|
for<'it> O: AsIter<'it, Item = T>,
|
||||||
N: IsNovel<T>,
|
N: IsNovel<T>,
|
||||||
I: Input,
|
I: Input,
|
||||||
S: HasNamedMetadata + HasClientPerfMonitor + Debug,
|
S: HasNamedMetadata + HasClientPerfMonitor + Debug,
|
||||||
@ -417,7 +417,7 @@ where
|
|||||||
impl<I, O, S> Feedback<I, S> for MapFeedback<I, DifferentIsNovel, O, MaxReducer, S, u8>
|
impl<I, O, S> Feedback<I, S> for MapFeedback<I, DifferentIsNovel, O, MaxReducer, S, u8>
|
||||||
where
|
where
|
||||||
O: MapObserver<Entry = u8> + AsSlice<u8>,
|
O: MapObserver<Entry = u8> + AsSlice<u8>,
|
||||||
for<'it> O: AsRefIterator<'it, Item = u8>,
|
for<'it> O: AsIter<'it, Item = u8>,
|
||||||
I: Input,
|
I: Input,
|
||||||
S: HasNamedMetadata + HasClientPerfMonitor + Debug,
|
S: HasNamedMetadata + HasClientPerfMonitor + Debug,
|
||||||
{
|
{
|
||||||
@ -539,7 +539,7 @@ where
|
|||||||
R: Reducer<T>,
|
R: Reducer<T>,
|
||||||
N: IsNovel<T>,
|
N: IsNovel<T>,
|
||||||
O: MapObserver<Entry = T>,
|
O: MapObserver<Entry = T>,
|
||||||
for<'it> O: AsRefIterator<'it, Item = T>,
|
for<'it> O: AsIter<'it, Item = T>,
|
||||||
S: HasNamedMetadata,
|
S: HasNamedMetadata,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -554,7 +554,7 @@ where
|
|||||||
R: Reducer<T>,
|
R: Reducer<T>,
|
||||||
N: IsNovel<T>,
|
N: IsNovel<T>,
|
||||||
O: MapObserver<Entry = T>,
|
O: MapObserver<Entry = T>,
|
||||||
for<'it> O: AsRefIterator<'it, Item = T>,
|
for<'it> O: AsIter<'it, Item = T>,
|
||||||
S: HasNamedMetadata,
|
S: HasNamedMetadata,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -572,7 +572,7 @@ where
|
|||||||
T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug,
|
T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug,
|
||||||
R: Reducer<T>,
|
R: Reducer<T>,
|
||||||
O: MapObserver<Entry = T>,
|
O: MapObserver<Entry = T>,
|
||||||
for<'it> O: AsRefIterator<'it, Item = T>,
|
for<'it> O: AsIter<'it, Item = T>,
|
||||||
N: IsNovel<T>,
|
N: IsNovel<T>,
|
||||||
I: Input,
|
I: Input,
|
||||||
S: HasNamedMetadata + HasClientPerfMonitor + Debug,
|
S: HasNamedMetadata + HasClientPerfMonitor + Debug,
|
||||||
@ -664,11 +664,7 @@ where
|
|||||||
|
|
||||||
let history_map = map_state.history_map.as_mut_slice();
|
let history_map = map_state.history_map.as_mut_slice();
|
||||||
|
|
||||||
for (i, (item, history)) in observer
|
for (i, (item, history)) in observer.as_iter().zip(history_map.iter_mut()).enumerate() {
|
||||||
.as_ref_iter()
|
|
||||||
.zip(history_map.iter_mut())
|
|
||||||
.enumerate()
|
|
||||||
{
|
|
||||||
let reduced = R::reduce(*history, *item);
|
let reduced = R::reduce(*history, *item);
|
||||||
if N::is_novel(*history, reduced) {
|
if N::is_novel(*history, reduced) {
|
||||||
*history = reduced;
|
*history = reduced;
|
||||||
@ -716,7 +712,7 @@ pub struct ReachabilityFeedback<O> {
|
|||||||
impl<O> ReachabilityFeedback<O>
|
impl<O> ReachabilityFeedback<O>
|
||||||
where
|
where
|
||||||
O: MapObserver<Entry = usize>,
|
O: MapObserver<Entry = usize>,
|
||||||
for<'it> O: AsRefIterator<'it, Item = usize>,
|
for<'it> O: AsIter<'it, Item = usize>,
|
||||||
{
|
{
|
||||||
/// Creates a new [`ReachabilityFeedback`] for a [`MapObserver`].
|
/// Creates a new [`ReachabilityFeedback`] for a [`MapObserver`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@ -743,7 +739,7 @@ impl<I, O, S> Feedback<I, S> for ReachabilityFeedback<O>
|
|||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
O: MapObserver<Entry = usize>,
|
O: MapObserver<Entry = usize>,
|
||||||
for<'it> O: AsRefIterator<'it, Item = usize>,
|
for<'it> O: AsIter<'it, Item = usize>,
|
||||||
S: HasClientPerfMonitor,
|
S: HasClientPerfMonitor,
|
||||||
{
|
{
|
||||||
#[allow(clippy::wrong_self_convention)]
|
#[allow(clippy::wrong_self_convention)]
|
||||||
@ -763,7 +759,7 @@ where
|
|||||||
let observer = observers.match_name::<O>(&self.name).unwrap();
|
let observer = observers.match_name::<O>(&self.name).unwrap();
|
||||||
let mut hit_target: bool = false;
|
let mut hit_target: bool = false;
|
||||||
//check if we've hit any targets.
|
//check if we've hit any targets.
|
||||||
for (i, &elem) in observer.as_ref_iter().enumerate() {
|
for (i, &elem) in observer.as_iter().enumerate() {
|
||||||
if elem > 0 {
|
if elem > 0 {
|
||||||
self.target_idx.push(i);
|
self.target_idx.push(i);
|
||||||
hit_target = true;
|
hit_target = true;
|
||||||
@ -793,7 +789,7 @@ where
|
|||||||
impl<O> Named for ReachabilityFeedback<O>
|
impl<O> Named for ReachabilityFeedback<O>
|
||||||
where
|
where
|
||||||
O: MapObserver<Entry = usize>,
|
O: MapObserver<Entry = usize>,
|
||||||
for<'it> O: AsRefIterator<'it, Item = usize>,
|
for<'it> O: AsIter<'it, Item = usize>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
|
@ -20,13 +20,53 @@ use crate::{
|
|||||||
bolts::{
|
bolts::{
|
||||||
ownedref::{OwnedRefMut, OwnedSliceMut},
|
ownedref::{OwnedRefMut, OwnedSliceMut},
|
||||||
tuples::Named,
|
tuples::Named,
|
||||||
AsMutIterator, AsMutSlice, AsRefIterator, AsSlice, HasLen,
|
AsIter, AsIterMut, AsMutSlice, AsSlice, HasLen,
|
||||||
},
|
},
|
||||||
executors::ExitKind,
|
executors::ExitKind,
|
||||||
observers::Observer,
|
observers::Observer,
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Hitcounts class lookup
|
||||||
|
static COUNT_CLASS_LOOKUP: [u8; 256] = [
|
||||||
|
0, 1, 2, 4, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||||
|
32, 32, 32, 32, 32, 32, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||||
|
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||||
|
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||||
|
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||||
|
64, 64, 64, 64, 64, 64, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
|
||||||
|
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
|
||||||
|
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
|
||||||
|
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
|
||||||
|
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
|
||||||
|
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
|
||||||
|
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
|
||||||
|
];
|
||||||
|
|
||||||
|
/// Hitcounts class lookup for 16-byte values
|
||||||
|
static mut COUNT_CLASS_LOOKUP_16: Vec<u16> = vec![];
|
||||||
|
|
||||||
|
/// Initialize the 16-byte hitcounts map
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Calling this from multiple threads may be racey and hence leak 65k mem
|
||||||
|
fn init_count_class_16() {
|
||||||
|
unsafe {
|
||||||
|
if !COUNT_CLASS_LOOKUP_16.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
COUNT_CLASS_LOOKUP_16 = vec![0; 65536];
|
||||||
|
for i in 0..256 {
|
||||||
|
for j in 0..256 {
|
||||||
|
COUNT_CLASS_LOOKUP_16[(i << 8) + j] =
|
||||||
|
(u16::from(COUNT_CLASS_LOOKUP[i]) << 8) | u16::from(COUNT_CLASS_LOOKUP[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Compute the hash of a slice
|
/// Compute the hash of a slice
|
||||||
fn hash_slice<T>(slice: &[T]) -> u64 {
|
fn hash_slice<T>(slice: &[T]) -> u64 {
|
||||||
let mut hasher = AHasher::new_with_keys(0, 0);
|
let mut hasher = AHasher::new_with_keys(0, 0);
|
||||||
@ -115,7 +155,7 @@ where
|
|||||||
|
|
||||||
/// A Simple iterator calling `MapObserver::get_mut`
|
/// A Simple iterator calling `MapObserver::get_mut`
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MapObserverSimpleIteratoMut<'a, O>
|
pub struct MapObserverSimpleIteratorMut<'a, O>
|
||||||
where
|
where
|
||||||
O: 'a + MapObserver,
|
O: 'a + MapObserver,
|
||||||
{
|
{
|
||||||
@ -124,7 +164,7 @@ where
|
|||||||
phantom: PhantomData<&'a u8>,
|
phantom: PhantomData<&'a u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, O> Iterator for MapObserverSimpleIteratoMut<'a, O>
|
impl<'a, O> Iterator for MapObserverSimpleIteratorMut<'a, O>
|
||||||
where
|
where
|
||||||
O: 'a + MapObserver,
|
O: 'a + MapObserver,
|
||||||
{
|
{
|
||||||
@ -194,7 +234,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'it, T> AsRefIterator<'it> for StdMapObserver<'a, T>
|
impl<'a, 'it, T> AsIter<'it> for StdMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Bounded
|
T: Bounded
|
||||||
+ PartialEq
|
+ PartialEq
|
||||||
@ -208,13 +248,13 @@ where
|
|||||||
type Item = T;
|
type Item = T;
|
||||||
type IntoIter = Iter<'it, T>;
|
type IntoIter = Iter<'it, T>;
|
||||||
|
|
||||||
fn as_ref_iter(&'it self) -> Self::IntoIter {
|
fn as_iter(&'it self) -> Self::IntoIter {
|
||||||
let cnt = self.usable_count();
|
let cnt = self.usable_count();
|
||||||
self.as_slice()[..cnt].iter()
|
self.as_slice()[..cnt].iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'it, T> AsMutIterator<'it> for StdMapObserver<'a, T>
|
impl<'a, 'it, T> AsIterMut<'it> for StdMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Bounded
|
T: Bounded
|
||||||
+ PartialEq
|
+ PartialEq
|
||||||
@ -228,7 +268,7 @@ where
|
|||||||
type Item = T;
|
type Item = T;
|
||||||
type IntoIter = IterMut<'it, T>;
|
type IntoIter = IterMut<'it, T>;
|
||||||
|
|
||||||
fn as_mut_iter(&'it mut self) -> Self::IntoIter {
|
fn as_iter_mut(&'it mut self) -> Self::IntoIter {
|
||||||
let cnt = self.usable_count();
|
let cnt = self.usable_count();
|
||||||
self.as_mut_slice()[..cnt].iter_mut()
|
self.as_mut_slice()[..cnt].iter_mut()
|
||||||
}
|
}
|
||||||
@ -489,7 +529,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'it, T, const N: usize> AsRefIterator<'it> for ConstMapObserver<'a, T, N>
|
impl<'a, 'it, T, const N: usize> AsIter<'it> for ConstMapObserver<'a, T, N>
|
||||||
where
|
where
|
||||||
T: Bounded
|
T: Bounded
|
||||||
+ PartialEq
|
+ PartialEq
|
||||||
@ -503,13 +543,13 @@ where
|
|||||||
type Item = T;
|
type Item = T;
|
||||||
type IntoIter = Iter<'it, T>;
|
type IntoIter = Iter<'it, T>;
|
||||||
|
|
||||||
fn as_ref_iter(&'it self) -> Self::IntoIter {
|
fn as_iter(&'it self) -> Self::IntoIter {
|
||||||
let cnt = self.usable_count();
|
let cnt = self.usable_count();
|
||||||
self.as_slice()[..cnt].iter()
|
self.as_slice()[..cnt].iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'it, T, const N: usize> AsMutIterator<'it> for ConstMapObserver<'a, T, N>
|
impl<'a, 'it, T, const N: usize> AsIterMut<'it> for ConstMapObserver<'a, T, N>
|
||||||
where
|
where
|
||||||
T: Bounded
|
T: Bounded
|
||||||
+ PartialEq
|
+ PartialEq
|
||||||
@ -523,7 +563,7 @@ where
|
|||||||
type Item = T;
|
type Item = T;
|
||||||
type IntoIter = IterMut<'it, T>;
|
type IntoIter = IterMut<'it, T>;
|
||||||
|
|
||||||
fn as_mut_iter(&'it mut self) -> Self::IntoIter {
|
fn as_iter_mut(&'it mut self) -> Self::IntoIter {
|
||||||
let cnt = self.usable_count();
|
let cnt = self.usable_count();
|
||||||
self.as_mut_slice()[..cnt].iter_mut()
|
self.as_mut_slice()[..cnt].iter_mut()
|
||||||
}
|
}
|
||||||
@ -756,11 +796,11 @@ where
|
|||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
self.map.as_slice().len()
|
*self.size.as_ref()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'it, T> AsRefIterator<'it> for VariableMapObserver<'a, T>
|
impl<'a, 'it, T> AsIter<'it> for VariableMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Bounded
|
T: Bounded
|
||||||
+ PartialEq
|
+ PartialEq
|
||||||
@ -774,13 +814,13 @@ where
|
|||||||
type Item = T;
|
type Item = T;
|
||||||
type IntoIter = Iter<'it, T>;
|
type IntoIter = Iter<'it, T>;
|
||||||
|
|
||||||
fn as_ref_iter(&'it self) -> Self::IntoIter {
|
fn as_iter(&'it self) -> Self::IntoIter {
|
||||||
let cnt = self.usable_count();
|
let cnt = self.usable_count();
|
||||||
self.as_slice()[..cnt].iter()
|
self.as_slice()[..cnt].iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'it, T> AsMutIterator<'it> for VariableMapObserver<'a, T>
|
impl<'a, 'it, T> AsIterMut<'it> for VariableMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Bounded
|
T: Bounded
|
||||||
+ PartialEq
|
+ PartialEq
|
||||||
@ -794,7 +834,7 @@ where
|
|||||||
type Item = T;
|
type Item = T;
|
||||||
type IntoIter = IterMut<'it, T>;
|
type IntoIter = IterMut<'it, T>;
|
||||||
|
|
||||||
fn as_mut_iter(&'it mut self) -> Self::IntoIter {
|
fn as_iter_mut(&'it mut self) -> Self::IntoIter {
|
||||||
let cnt = self.usable_count();
|
let cnt = self.usable_count();
|
||||||
self.as_mut_slice()[..cnt].iter_mut()
|
self.as_mut_slice()[..cnt].iter_mut()
|
||||||
}
|
}
|
||||||
@ -984,7 +1024,10 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Map observer with hitcounts postprocessing
|
/// Map observer with AFL-like hitcounts postprocessing
|
||||||
|
///
|
||||||
|
/// [`MapObserver`]s that are not slice-backed,
|
||||||
|
/// such as [`MultiMapObserver`], can use [`HitcountsIterableMapObserver`] instead.
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
#[serde(bound = "M: serde::de::DeserializeOwned")]
|
#[serde(bound = "M: serde::de::DeserializeOwned")]
|
||||||
pub struct HitcountsMapObserver<M>
|
pub struct HitcountsMapObserver<M>
|
||||||
@ -994,43 +1037,9 @@ where
|
|||||||
base: M,
|
base: M,
|
||||||
}
|
}
|
||||||
|
|
||||||
static COUNT_CLASS_LOOKUP: [u8; 256] = [
|
|
||||||
0, 1, 2, 4, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
|
||||||
32, 32, 32, 32, 32, 32, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
|
||||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
|
||||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
|
||||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
|
||||||
64, 64, 64, 64, 64, 64, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
|
|
||||||
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
|
|
||||||
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
|
|
||||||
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
|
|
||||||
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
|
|
||||||
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
|
|
||||||
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
|
|
||||||
];
|
|
||||||
|
|
||||||
static mut COUNT_CLASS_LOOKUP_16: Vec<u16> = vec![];
|
|
||||||
|
|
||||||
fn init_count_class_16() {
|
|
||||||
unsafe {
|
|
||||||
if !COUNT_CLASS_LOOKUP_16.is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
COUNT_CLASS_LOOKUP_16 = vec![0; 65536];
|
|
||||||
for i in 0..256 {
|
|
||||||
for j in 0..256 {
|
|
||||||
COUNT_CLASS_LOOKUP_16[(i << 8) + j] =
|
|
||||||
(u16::from(COUNT_CLASS_LOOKUP[i]) << 8) | u16::from(COUNT_CLASS_LOOKUP[j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, S, M> Observer<I, S> for HitcountsMapObserver<M>
|
impl<I, S, M> Observer<I, S> for HitcountsMapObserver<M>
|
||||||
where
|
where
|
||||||
M: MapObserver<Entry = u8> + Observer<I, S> + AsMutSlice<u8>,
|
M: MapObserver<Entry = u8> + Observer<I, S> + AsMutSlice<u8>,
|
||||||
for<'it> M: AsMutIterator<'it, Item = u8>,
|
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn pre_exec(&mut self, state: &mut S, input: &I) -> Result<(), Error> {
|
fn pre_exec(&mut self, state: &mut S, input: &I) -> Result<(), Error> {
|
||||||
@ -1051,6 +1060,7 @@ where
|
|||||||
|
|
||||||
let cnt = len / 2;
|
let cnt = len / 2;
|
||||||
let map16 = unsafe { core::slice::from_raw_parts_mut(map.as_mut_ptr() as *mut u16, cnt) };
|
let map16 = unsafe { core::slice::from_raw_parts_mut(map.as_mut_ptr() as *mut u16, cnt) };
|
||||||
|
// 2022-07: Adding `enumerate` here increases execution speed/register allocation on x86_64.
|
||||||
for (_i, item) in map16[0..cnt].iter_mut().enumerate() {
|
for (_i, item) in map16[0..cnt].iter_mut().enumerate() {
|
||||||
unsafe {
|
unsafe {
|
||||||
*item = *COUNT_CLASS_LOOKUP_16.get_unchecked(*item as usize);
|
*item = *COUNT_CLASS_LOOKUP_16.get_unchecked(*item as usize);
|
||||||
@ -1083,7 +1093,6 @@ where
|
|||||||
impl<M> MapObserver for HitcountsMapObserver<M>
|
impl<M> MapObserver for HitcountsMapObserver<M>
|
||||||
where
|
where
|
||||||
M: MapObserver<Entry = u8>,
|
M: MapObserver<Entry = u8>,
|
||||||
for<'it> M: AsMutIterator<'it, Item = u8>,
|
|
||||||
{
|
{
|
||||||
type Entry = u8;
|
type Entry = u8;
|
||||||
|
|
||||||
@ -1165,27 +1174,27 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'it, M> AsRefIterator<'it> for HitcountsMapObserver<M>
|
impl<'it, M> AsIter<'it> for HitcountsMapObserver<M>
|
||||||
where
|
where
|
||||||
M: Named + Serialize + serde::de::DeserializeOwned + AsRefIterator<'it, Item = u8>,
|
M: Named + Serialize + serde::de::DeserializeOwned + AsIter<'it, Item = u8>,
|
||||||
{
|
{
|
||||||
type Item = u8;
|
type Item = u8;
|
||||||
type IntoIter = <M as AsRefIterator<'it>>::IntoIter;
|
type IntoIter = <M as AsIter<'it>>::IntoIter;
|
||||||
|
|
||||||
fn as_ref_iter(&'it self) -> Self::IntoIter {
|
fn as_iter(&'it self) -> Self::IntoIter {
|
||||||
self.base.as_ref_iter()
|
self.base.as_iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'it, M> AsMutIterator<'it> for HitcountsMapObserver<M>
|
impl<'it, M> AsIterMut<'it> for HitcountsMapObserver<M>
|
||||||
where
|
where
|
||||||
M: Named + Serialize + serde::de::DeserializeOwned + AsMutIterator<'it, Item = u8>,
|
M: Named + Serialize + serde::de::DeserializeOwned + AsIterMut<'it, Item = u8>,
|
||||||
{
|
{
|
||||||
type Item = u8;
|
type Item = u8;
|
||||||
type IntoIter = <M as AsMutIterator<'it>>::IntoIter;
|
type IntoIter = <M as AsIterMut<'it>>::IntoIter;
|
||||||
|
|
||||||
fn as_mut_iter(&'it mut self) -> Self::IntoIter {
|
fn as_iter_mut(&'it mut self) -> Self::IntoIter {
|
||||||
self.base.as_mut_iter()
|
self.base.as_iter_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1215,6 +1224,194 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Map observer with hitcounts postprocessing
|
||||||
|
/// Less optimized version for non-slice iterators.
|
||||||
|
/// Slice-backed observers should use a [`HitcountsMapObserver`].
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
#[serde(bound = "M: serde::de::DeserializeOwned")]
|
||||||
|
pub struct HitcountsIterableMapObserver<M>
|
||||||
|
where
|
||||||
|
M: Serialize,
|
||||||
|
{
|
||||||
|
base: M,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, S, M> Observer<I, S> for HitcountsIterableMapObserver<M>
|
||||||
|
where
|
||||||
|
M: MapObserver<Entry = u8> + Observer<I, S>,
|
||||||
|
for<'it> M: AsIterMut<'it, Item = u8>,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn pre_exec(&mut self, state: &mut S, input: &I) -> Result<(), Error> {
|
||||||
|
self.base.pre_exec(state, input)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
|
fn post_exec(&mut self, state: &mut S, input: &I, exit_kind: &ExitKind) -> Result<(), Error> {
|
||||||
|
for item in self.as_iter_mut() {
|
||||||
|
*item = unsafe { *COUNT_CLASS_LOOKUP.get_unchecked((*item) as usize) };
|
||||||
|
}
|
||||||
|
|
||||||
|
self.base.post_exec(state, input, exit_kind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M> Named for HitcountsIterableMapObserver<M>
|
||||||
|
where
|
||||||
|
M: Named + Serialize + serde::de::DeserializeOwned,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
self.base.name()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M> HasLen for HitcountsIterableMapObserver<M>
|
||||||
|
where
|
||||||
|
M: MapObserver,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.base.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M> MapObserver for HitcountsIterableMapObserver<M>
|
||||||
|
where
|
||||||
|
M: MapObserver<Entry = u8>,
|
||||||
|
for<'it> M: AsIterMut<'it, Item = u8>,
|
||||||
|
{
|
||||||
|
type Entry = u8;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn initial(&self) -> u8 {
|
||||||
|
self.base.initial()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn initial_mut(&mut self) -> &mut u8 {
|
||||||
|
self.base.initial_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn usable_count(&self) -> usize {
|
||||||
|
self.base.usable_count()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get(&self, idx: usize) -> &u8 {
|
||||||
|
self.base.get(idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_mut(&mut self, idx: usize) -> &mut u8 {
|
||||||
|
self.base.get_mut(idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Count the set bytes in the map
|
||||||
|
fn count_bytes(&self) -> u64 {
|
||||||
|
self.base.count_bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reset the map
|
||||||
|
#[inline]
|
||||||
|
fn reset_map(&mut self) -> Result<(), Error> {
|
||||||
|
self.base.reset_map()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hash(&self) -> u64 {
|
||||||
|
self.base.hash()
|
||||||
|
}
|
||||||
|
fn to_vec(&self) -> Vec<u8> {
|
||||||
|
self.base.to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn how_many_set(&self, indexes: &[usize]) -> usize {
|
||||||
|
self.base.how_many_set(indexes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M> AsSlice<u8> for HitcountsIterableMapObserver<M>
|
||||||
|
where
|
||||||
|
M: MapObserver + AsSlice<u8>,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn as_slice(&self) -> &[u8] {
|
||||||
|
self.base.as_slice()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<M> AsMutSlice<u8> for HitcountsIterableMapObserver<M>
|
||||||
|
where
|
||||||
|
M: MapObserver + AsMutSlice<u8>,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn as_mut_slice(&mut self) -> &mut [u8] {
|
||||||
|
self.base.as_mut_slice()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M> HitcountsIterableMapObserver<M>
|
||||||
|
where
|
||||||
|
M: Serialize + serde::de::DeserializeOwned,
|
||||||
|
{
|
||||||
|
/// Creates a new [`MapObserver`]
|
||||||
|
pub fn new(base: M) -> Self {
|
||||||
|
init_count_class_16();
|
||||||
|
Self { base }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'it, M> AsIter<'it> for HitcountsIterableMapObserver<M>
|
||||||
|
where
|
||||||
|
M: Named + Serialize + serde::de::DeserializeOwned + AsIter<'it, Item = u8>,
|
||||||
|
{
|
||||||
|
type Item = u8;
|
||||||
|
type IntoIter = <M as AsIter<'it>>::IntoIter;
|
||||||
|
|
||||||
|
fn as_iter(&'it self) -> Self::IntoIter {
|
||||||
|
self.base.as_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'it, M> AsIterMut<'it> for HitcountsIterableMapObserver<M>
|
||||||
|
where
|
||||||
|
M: Named + Serialize + serde::de::DeserializeOwned + AsIterMut<'it, Item = u8>,
|
||||||
|
{
|
||||||
|
type Item = u8;
|
||||||
|
type IntoIter = <M as AsIterMut<'it>>::IntoIter;
|
||||||
|
|
||||||
|
fn as_iter_mut(&'it mut self) -> Self::IntoIter {
|
||||||
|
self.base.as_iter_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'it, M> IntoIterator for &'it HitcountsIterableMapObserver<M>
|
||||||
|
where
|
||||||
|
M: Named + Serialize + serde::de::DeserializeOwned,
|
||||||
|
&'it M: IntoIterator<Item = &'it u8>,
|
||||||
|
{
|
||||||
|
type Item = &'it u8;
|
||||||
|
type IntoIter = <&'it M as IntoIterator>::IntoIter;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.base.into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'it, M> IntoIterator for &'it mut HitcountsIterableMapObserver<M>
|
||||||
|
where
|
||||||
|
M: Named + Serialize + serde::de::DeserializeOwned,
|
||||||
|
&'it mut M: IntoIterator<Item = &'it mut u8>,
|
||||||
|
{
|
||||||
|
type Item = &'it mut u8;
|
||||||
|
type IntoIter = <&'it mut M as IntoIterator>::IntoIter;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.base.into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The Multi Map Observer merge different maps into one observer
|
/// The Multi Map Observer merge different maps into one observer
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
#[serde(bound = "T: serde::de::DeserializeOwned")]
|
#[serde(bound = "T: serde::de::DeserializeOwned")]
|
||||||
@ -1423,7 +1620,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'it, T> AsRefIterator<'it> for MultiMapObserver<'a, T>
|
impl<'a, 'it, T> AsIter<'it> for MultiMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
||||||
'a: 'it,
|
'a: 'it,
|
||||||
@ -1431,12 +1628,12 @@ where
|
|||||||
type Item = T;
|
type Item = T;
|
||||||
type IntoIter = Flatten<Iter<'it, OwnedSliceMut<'a, T>>>;
|
type IntoIter = Flatten<Iter<'it, OwnedSliceMut<'a, T>>>;
|
||||||
|
|
||||||
fn as_ref_iter(&'it self) -> Self::IntoIter {
|
fn as_iter(&'it self) -> Self::IntoIter {
|
||||||
self.maps.iter().flatten()
|
self.maps.iter().flatten()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'it, T> AsMutIterator<'it> for MultiMapObserver<'a, T>
|
impl<'a, 'it, T> AsIterMut<'it> for MultiMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
||||||
'a: 'it,
|
'a: 'it,
|
||||||
@ -1444,7 +1641,7 @@ where
|
|||||||
type Item = T;
|
type Item = T;
|
||||||
type IntoIter = Flatten<IterMut<'it, OwnedSliceMut<'a, T>>>;
|
type IntoIter = Flatten<IterMut<'it, OwnedSliceMut<'a, T>>>;
|
||||||
|
|
||||||
fn as_mut_iter(&'it mut self) -> Self::IntoIter {
|
fn as_iter_mut(&'it mut self) -> Self::IntoIter {
|
||||||
self.maps.iter_mut().flatten()
|
self.maps.iter_mut().flatten()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1518,26 +1715,26 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'it, T> AsRefIterator<'it> for OwnedMapObserver<T>
|
impl<'it, T> AsIter<'it> for OwnedMapObserver<T>
|
||||||
where
|
where
|
||||||
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
||||||
{
|
{
|
||||||
type Item = T;
|
type Item = T;
|
||||||
type IntoIter = Iter<'it, T>;
|
type IntoIter = Iter<'it, T>;
|
||||||
|
|
||||||
fn as_ref_iter(&'it self) -> Self::IntoIter {
|
fn as_iter(&'it self) -> Self::IntoIter {
|
||||||
self.as_slice().iter()
|
self.as_slice().iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'it, T> AsMutIterator<'it> for OwnedMapObserver<T>
|
impl<'it, T> AsIterMut<'it> for OwnedMapObserver<T>
|
||||||
where
|
where
|
||||||
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
||||||
{
|
{
|
||||||
type Item = T;
|
type Item = T;
|
||||||
type IntoIter = IterMut<'it, T>;
|
type IntoIter = IterMut<'it, T>;
|
||||||
|
|
||||||
fn as_mut_iter(&'it mut self) -> Self::IntoIter {
|
fn as_iter_mut(&'it mut self) -> Self::IntoIter {
|
||||||
self.as_mut_slice().iter_mut()
|
self.as_mut_slice().iter_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1699,8 +1896,8 @@ where
|
|||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub mod pybind {
|
pub mod pybind {
|
||||||
use super::{
|
use super::{
|
||||||
AsMutIterator, AsMutSlice, AsRefIterator, AsSlice, Debug, Error, HasLen, Iter, IterMut,
|
AsIter, AsIterMut, AsMutSlice, AsSlice, Debug, Error, HasLen, Iter, IterMut, MapObserver,
|
||||||
MapObserver, Named, Observer, OwnedMapObserver, StdMapObserver, String, Vec,
|
Named, Observer, OwnedMapObserver, StdMapObserver, String, Vec,
|
||||||
};
|
};
|
||||||
use crate::observers::pybind::PythonObserver;
|
use crate::observers::pybind::PythonObserver;
|
||||||
use concat_idents::concat_idents;
|
use concat_idents::concat_idents;
|
||||||
@ -1934,21 +2131,21 @@ pub mod pybind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'it> AsRefIterator<'it> for $struct_name_trait {
|
impl<'it> AsIter<'it> for $struct_name_trait {
|
||||||
type Item = $datatype;
|
type Item = $datatype;
|
||||||
type IntoIter = Iter<'it, $datatype>;
|
type IntoIter = Iter<'it, $datatype>;
|
||||||
|
|
||||||
fn as_ref_iter(&'it self) -> Self::IntoIter {
|
fn as_iter(&'it self) -> Self::IntoIter {
|
||||||
mapob_unwrap_me!($wrapper_name, self.wrapper, m, { unsafe { std::mem::transmute::<_, Self::IntoIter>(m.as_ref_iter()) } })
|
mapob_unwrap_me!($wrapper_name, self.wrapper, m, { unsafe { std::mem::transmute::<_, Self::IntoIter>(m.as_iter()) } })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'it> AsMutIterator<'it> for $struct_name_trait {
|
impl<'it> AsIterMut<'it> for $struct_name_trait {
|
||||||
type Item = $datatype;
|
type Item = $datatype;
|
||||||
type IntoIter = IterMut<'it, $datatype>;
|
type IntoIter = IterMut<'it, $datatype>;
|
||||||
|
|
||||||
fn as_mut_iter(&'it mut self) -> Self::IntoIter {
|
fn as_iter_mut(&'it mut self) -> Self::IntoIter {
|
||||||
mapob_unwrap_me_mut!($wrapper_name, self.wrapper, m, { unsafe { std::mem::transmute::<_, Self::IntoIter>(m.as_mut_iter()) } })
|
mapob_unwrap_me_mut!($wrapper_name, self.wrapper, m, { unsafe { std::mem::transmute::<_, Self::IntoIter>(m.as_iter_mut()) } })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//! The calibration stage. The fuzzer measures the average exec time and the bitmap size.
|
//! The calibration stage. The fuzzer measures the average exec time and the bitmap size.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::{current_time, tuples::Named, AsRefIterator},
|
bolts::{current_time, tuples::Named, AsIter},
|
||||||
corpus::{Corpus, SchedulerTestcaseMetaData},
|
corpus::{Corpus, SchedulerTestcaseMetaData},
|
||||||
events::{EventFirer, LogSeverity},
|
events::{EventFirer, LogSeverity},
|
||||||
executors::{Executor, ExitKind, HasObservers},
|
executors::{Executor, ExitKind, HasObservers},
|
||||||
@ -240,7 +240,7 @@ where
|
|||||||
O::Entry:
|
O::Entry:
|
||||||
PartialEq + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
PartialEq + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
||||||
R: Reducer<O::Entry>,
|
R: Reducer<O::Entry>,
|
||||||
for<'it> O: AsRefIterator<'it, Item = O::Entry>,
|
for<'it> O: AsIter<'it, Item = O::Entry>,
|
||||||
N: IsNovel<O::Entry>,
|
N: IsNovel<O::Entry>,
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user