implemented MapMaxPow2Feedback (#371)
* implemented MapMaxPow2Feedback * using num-traits for qemu as well * moved back to Num for float fun * OneOrFilled Feedback
This commit is contained in:
parent
3e85cf22de
commit
fff7cbd90f
@ -46,7 +46,7 @@ serial_test = "0.5"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
tuple_list = { version = "0.1.3" }
|
tuple_list = { version = "0.1.3" }
|
||||||
hashbrown = { version = "0.11", features = ["serde", "ahash-compile-time-rng"], default-features=false } # A faster hashmap, nostd compatible
|
hashbrown = { version = "0.11", features = ["serde", "ahash-compile-time-rng"], default-features=false } # A faster hashmap, nostd compatible
|
||||||
num = { version = "0.4.0", default-features = false }
|
num-traits = { version = "0.2", default-features = false }
|
||||||
xxhash-rust = { version = "0.8.2", features = ["xxh3"] } # xxh3 hashing for rust
|
xxhash-rust = { version = "0.8.2", features = ["xxh3"] } # xxh3 hashing for rust
|
||||||
serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib
|
serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib
|
||||||
erased-serde = { version = "0.3.12", default-features = false, features = ["alloc"] } # erased serde
|
erased-serde = { version = "0.3.12", default-features = false, features = ["alloc"] } # erased serde
|
||||||
|
@ -5,7 +5,7 @@ use alloc::{
|
|||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use num::Integer;
|
use num_traits::PrimInt;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -22,26 +22,41 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// A [`MapFeedback`] that strives to maximize the map contents.
|
/// A [`MapFeedback`] that strives to maximize the map contents.
|
||||||
pub type MaxMapFeedback<FT, I, O, S, T> = MapFeedback<FT, I, O, MaxReducer, S, T>;
|
pub type MaxMapFeedback<FT, I, O, S, T> = MapFeedback<FT, I, MapNopFilter, O, MaxReducer, S, T>;
|
||||||
/// A [`MapFeedback`] that strives to minimize the map contents.
|
/// A [`MapFeedback`] that strives to minimize the map contents.
|
||||||
pub type MinMapFeedback<FT, I, O, S, T> = MapFeedback<FT, I, O, MinReducer, S, T>;
|
pub type MinMapFeedback<FT, I, O, S, T> = MapFeedback<FT, I, MapNopFilter, O, MinReducer, S, T>;
|
||||||
|
|
||||||
/// A Reducer function is used to aggregate values for the novelty search
|
/// A [`MapFeedback`] that strives to maximize the map contents,
|
||||||
|
/// but only, if a value is larger than `pow2` of the previous.
|
||||||
|
pub type MaxMapPow2Feedback<FT, I, O, S, T> =
|
||||||
|
MapFeedback<FT, I, MaxMapPow2Filter, O, MaxReducer, S, T>;
|
||||||
|
/// A [`MapFeedback`] that strives to maximize the map contents,
|
||||||
|
/// but only, if a value is larger than `pow2` of the previous.
|
||||||
|
pub type MaxMapOneOrFilledFeedback<FT, I, O, S, T> =
|
||||||
|
MapFeedback<FT, I, MaxMapOneOrFilledFilter, O, MaxReducer, S, T>;
|
||||||
|
|
||||||
|
/// A `Reducer` function is used to aggregate values for the novelty search
|
||||||
pub trait Reducer<T>: Serialize + serde::de::DeserializeOwned + 'static
|
pub trait Reducer<T>: Serialize + serde::de::DeserializeOwned + 'static
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
/// Reduce two values to one value, with the current [`Reducer`].
|
/// Reduce two values to one value, with the current [`Reducer`].
|
||||||
fn reduce(first: T, second: T) -> T;
|
fn reduce(first: T, second: T) -> T;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [`MaxReducer`] reduces [`Integer`] values and returns their maximum.
|
/// A [`MaxReducer`] reduces int values and returns their maximum.
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct MaxReducer {}
|
pub struct MaxReducer {}
|
||||||
|
|
||||||
impl<T> Reducer<T> for MaxReducer
|
impl<T> Reducer<T> for MaxReducer
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt
|
||||||
|
+ Default
|
||||||
|
+ Copy
|
||||||
|
+ 'static
|
||||||
|
+ serde::Serialize
|
||||||
|
+ serde::de::DeserializeOwned
|
||||||
|
+ PartialOrd,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn reduce(first: T, second: T) -> T {
|
fn reduce(first: T, second: T) -> T {
|
||||||
@ -53,13 +68,19 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [`MinReducer`] reduces [`Integer`] values and returns their minimum.
|
/// A [`MinReducer`] reduces int values and returns their minimum.
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct MinReducer {}
|
pub struct MinReducer {}
|
||||||
|
|
||||||
impl<T> Reducer<T> for MinReducer
|
impl<T> Reducer<T> for MinReducer
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt
|
||||||
|
+ Default
|
||||||
|
+ Copy
|
||||||
|
+ 'static
|
||||||
|
+ serde::Serialize
|
||||||
|
+ serde::de::DeserializeOwned
|
||||||
|
+ PartialOrd,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn reduce(first: T, second: T) -> T {
|
fn reduce(first: T, second: T) -> T {
|
||||||
@ -71,6 +92,79 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A `MapFindFilter` function gets called after the `MapFeedback` found a new entry.
|
||||||
|
pub trait MapFindFilter<T>: Serialize + serde::de::DeserializeOwned + 'static
|
||||||
|
where
|
||||||
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
|
{
|
||||||
|
/// If a new value in the [`MapFeedback`] was found,
|
||||||
|
/// this filter can decide if the result is intersting or not.
|
||||||
|
/// This way, you can restrict the finds further.
|
||||||
|
fn is_interesting(old: T, new: T) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A filter that never filters out any finds.
|
||||||
|
/// The default
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
pub struct MapNopFilter {}
|
||||||
|
|
||||||
|
impl<T> MapFindFilter<T> for MapNopFilter
|
||||||
|
where
|
||||||
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn is_interesting(_old: T, _new: T) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculate the next power of two
|
||||||
|
/// See <https://stackoverflow.com/a/66253960/1345238>
|
||||||
|
/// Will saturate at the max value.
|
||||||
|
/// In case of negative values, returns 1.
|
||||||
|
#[inline]
|
||||||
|
fn saturating_next_power_of_two<T: PrimInt>(n: T) -> T {
|
||||||
|
if n <= T::one() {
|
||||||
|
T::one()
|
||||||
|
} else {
|
||||||
|
(T::max_value() >> (n - T::one()).leading_zeros().try_into().unwrap())
|
||||||
|
.saturating_add(T::one())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A filter that only saves values which are at least the next pow2 class
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
pub struct MaxMapPow2Filter {}
|
||||||
|
impl<T> MapFindFilter<T> for MaxMapPow2Filter
|
||||||
|
where
|
||||||
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn is_interesting(old: T, new: T) -> bool {
|
||||||
|
// We use a trait so we build our numbers from scratch here.
|
||||||
|
// This way it works with Nums of any size.
|
||||||
|
if new <= old {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
let pow2 = saturating_next_power_of_two(old.saturating_add(T::one()));
|
||||||
|
new >= pow2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A filter that only saves values which are at least the next pow2 class
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
pub struct MaxMapOneOrFilledFilter {}
|
||||||
|
impl<T> MapFindFilter<T> for MaxMapOneOrFilledFilter
|
||||||
|
where
|
||||||
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn is_interesting(old: T, new: T) -> bool {
|
||||||
|
(new == T::one() || new == T::one() || new == T::max_value()) && new > old
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A testcase metadata holding a list of indexes of a map
|
/// A testcase metadata holding a list of indexes of a map
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct MapIndexesMetadata {
|
pub struct MapIndexesMetadata {
|
||||||
@ -136,7 +230,7 @@ impl MapNoveltiesMetadata {
|
|||||||
#[serde(bound = "T: serde::de::DeserializeOwned")]
|
#[serde(bound = "T: serde::de::DeserializeOwned")]
|
||||||
pub struct MapFeedbackState<T>
|
pub struct MapFeedbackState<T>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
/// Contains information about untouched entries
|
/// Contains information about untouched entries
|
||||||
pub history_map: Vec<T>,
|
pub history_map: Vec<T>,
|
||||||
@ -146,7 +240,7 @@ where
|
|||||||
|
|
||||||
impl<T> FeedbackState for MapFeedbackState<T>
|
impl<T> FeedbackState for MapFeedbackState<T>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
fn reset(&mut self) -> Result<(), Error> {
|
fn reset(&mut self) -> Result<(), Error> {
|
||||||
self.history_map.iter_mut().for_each(|x| *x = T::default());
|
self.history_map.iter_mut().for_each(|x| *x = T::default());
|
||||||
@ -156,7 +250,7 @@ where
|
|||||||
|
|
||||||
impl<T> Named for MapFeedbackState<T>
|
impl<T> Named for MapFeedbackState<T>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
@ -166,7 +260,7 @@ where
|
|||||||
|
|
||||||
impl<T> MapFeedbackState<T>
|
impl<T> MapFeedbackState<T>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
/// Create new `MapFeedbackState`
|
/// Create new `MapFeedbackState`
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@ -202,11 +296,12 @@ where
|
|||||||
/// The most common AFL-like feedback type
|
/// The most common AFL-like feedback type
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
#[serde(bound = "T: serde::de::DeserializeOwned")]
|
#[serde(bound = "T: serde::de::DeserializeOwned")]
|
||||||
pub struct MapFeedback<FT, I, O, R, S, T>
|
pub struct MapFeedback<FT, I, MF, O, R, S, T>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
R: Reducer<T>,
|
R: Reducer<T>,
|
||||||
O: MapObserver<T>,
|
O: MapObserver<T>,
|
||||||
|
MF: MapFindFilter<T>,
|
||||||
S: HasFeedbackStates<FT>,
|
S: HasFeedbackStates<FT>,
|
||||||
FT: FeedbackStatesTuple,
|
FT: FeedbackStatesTuple,
|
||||||
{
|
{
|
||||||
@ -219,14 +314,15 @@ where
|
|||||||
/// Name identifier of the observer
|
/// Name identifier of the observer
|
||||||
observer_name: String,
|
observer_name: String,
|
||||||
/// Phantom Data of Reducer
|
/// Phantom Data of Reducer
|
||||||
phantom: PhantomData<(FT, I, S, R, O, T)>,
|
phantom: PhantomData<(FT, I, MF, S, R, O, T)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, FT, O, R, S, T> Feedback<I, S> for MapFeedback<FT, I, O, R, S, T>
|
impl<FT, I, MF, O, R, S, T> Feedback<I, S> for MapFeedback<FT, I, MF, O, R, S, T>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
R: Reducer<T>,
|
R: Reducer<T>,
|
||||||
O: MapObserver<T>,
|
O: MapObserver<T>,
|
||||||
|
MF: MapFindFilter<T>,
|
||||||
I: Input,
|
I: Input,
|
||||||
S: HasFeedbackStates<FT> + HasClientPerfStats,
|
S: HasFeedbackStates<FT> + HasClientPerfStats,
|
||||||
FT: FeedbackStatesTuple,
|
FT: FeedbackStatesTuple,
|
||||||
@ -264,7 +360,7 @@ where
|
|||||||
let item = *observer.get(i);
|
let item = *observer.get(i);
|
||||||
|
|
||||||
let reduced = R::reduce(history, item);
|
let reduced = R::reduce(history, item);
|
||||||
if history != reduced {
|
if history != reduced && MF::is_interesting(history, reduced) {
|
||||||
map_state.history_map[i] = reduced;
|
map_state.history_map[i] = reduced;
|
||||||
interesting = true;
|
interesting = true;
|
||||||
self.novelties.as_mut().unwrap().push(i);
|
self.novelties.as_mut().unwrap().push(i);
|
||||||
@ -276,7 +372,7 @@ where
|
|||||||
let item = *observer.get(i);
|
let item = *observer.get(i);
|
||||||
|
|
||||||
let reduced = R::reduce(history, item);
|
let reduced = R::reduce(history, item);
|
||||||
if history != reduced {
|
if history != reduced && MF::is_interesting(history, reduced) {
|
||||||
map_state.history_map[i] = reduced;
|
map_state.history_map[i] = reduced;
|
||||||
interesting = true;
|
interesting = true;
|
||||||
}
|
}
|
||||||
@ -330,10 +426,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<FT, I, O, R, S, T> Named for MapFeedback<FT, I, O, R, S, T>
|
impl<FT, I, MF, O, R, S, T> Named for MapFeedback<FT, I, MF, O, R, S, T>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
R: Reducer<T>,
|
R: Reducer<T>,
|
||||||
|
MF: MapFindFilter<T>,
|
||||||
O: MapObserver<T>,
|
O: MapObserver<T>,
|
||||||
S: HasFeedbackStates<FT>,
|
S: HasFeedbackStates<FT>,
|
||||||
FT: FeedbackStatesTuple,
|
FT: FeedbackStatesTuple,
|
||||||
@ -344,10 +441,17 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<FT, I, O, R, S, T> MapFeedback<FT, I, O, R, S, T>
|
impl<FT, I, MF, O, R, S, T> MapFeedback<FT, I, MF, O, R, S, T>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt
|
||||||
|
+ Default
|
||||||
|
+ Copy
|
||||||
|
+ 'static
|
||||||
|
+ serde::Serialize
|
||||||
|
+ serde::de::DeserializeOwned
|
||||||
|
+ PartialOrd,
|
||||||
R: Reducer<T>,
|
R: Reducer<T>,
|
||||||
|
MF: MapFindFilter<T>,
|
||||||
O: MapObserver<T>,
|
O: MapObserver<T>,
|
||||||
S: HasFeedbackStates<FT>,
|
S: HasFeedbackStates<FT>,
|
||||||
FT: FeedbackStatesTuple,
|
FT: FeedbackStatesTuple,
|
||||||
@ -503,3 +607,28 @@ where
|
|||||||
self.name.as_str()
|
self.name.as_str()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::feedbacks::{MapFindFilter, MapNopFilter, MaxMapPow2Filter};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_map_max_pow2_filter() {
|
||||||
|
// sanity check
|
||||||
|
assert!(MapNopFilter::is_interesting(0_u8, 0));
|
||||||
|
|
||||||
|
assert!(!MaxMapPow2Filter::is_interesting(0_u8, 0));
|
||||||
|
assert!(MaxMapPow2Filter::is_interesting(0_u8, 1));
|
||||||
|
assert!(!MaxMapPow2Filter::is_interesting(1_u8, 1));
|
||||||
|
assert!(MaxMapPow2Filter::is_interesting(1_u8, 2));
|
||||||
|
assert!(!MaxMapPow2Filter::is_interesting(2_u8, 2));
|
||||||
|
assert!(!MaxMapPow2Filter::is_interesting(2_u8, 3));
|
||||||
|
assert!(MaxMapPow2Filter::is_interesting(2_u8, 4));
|
||||||
|
assert!(!MaxMapPow2Filter::is_interesting(128_u8, 128));
|
||||||
|
assert!(!MaxMapPow2Filter::is_interesting(129_u8, 128));
|
||||||
|
assert!(MaxMapPow2Filter::is_interesting(128_u8, 255));
|
||||||
|
assert!(!MaxMapPow2Filter::is_interesting(255_u8, 128));
|
||||||
|
assert!(MaxMapPow2Filter::is_interesting(254_u8, 255));
|
||||||
|
assert!(!MaxMapPow2Filter::is_interesting(255_u8, 255));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -10,7 +10,7 @@ use core::{
|
|||||||
slice::{from_raw_parts, from_raw_parts_mut},
|
slice::{from_raw_parts, from_raw_parts_mut},
|
||||||
};
|
};
|
||||||
use intervaltree::IntervalTree;
|
use intervaltree::IntervalTree;
|
||||||
use num::Integer;
|
use num_traits::PrimInt;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -26,7 +26,7 @@ use crate::{
|
|||||||
/// A [`MapObserver`] observes the static map, as oftentimes used for afl-like coverage information
|
/// A [`MapObserver`] observes the static map, as oftentimes used for afl-like coverage information
|
||||||
pub trait MapObserver<T>: HasLen + Named + serde::Serialize + serde::de::DeserializeOwned
|
pub trait MapObserver<T>: HasLen + Named + serde::Serialize + serde::de::DeserializeOwned
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy,
|
T: PrimInt + Default + Copy,
|
||||||
{
|
{
|
||||||
/// Get the map if the observer can be represented with a slice
|
/// Get the map if the observer can be represented with a slice
|
||||||
fn map(&self) -> Option<&[T]>;
|
fn map(&self) -> Option<&[T]>;
|
||||||
@ -108,7 +108,7 @@ where
|
|||||||
#[allow(clippy::unsafe_derive_deserialize)]
|
#[allow(clippy::unsafe_derive_deserialize)]
|
||||||
pub struct StdMapObserver<'a, T>
|
pub struct StdMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
map: OwnedSliceMut<'a, T>,
|
map: OwnedSliceMut<'a, T>,
|
||||||
initial: T,
|
initial: T,
|
||||||
@ -117,7 +117,7 @@ where
|
|||||||
|
|
||||||
impl<'a, I, S, T> Observer<I, S> for StdMapObserver<'a, T>
|
impl<'a, I, S, T> Observer<I, S> for StdMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
Self: MapObserver<T>,
|
Self: MapObserver<T>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -128,7 +128,7 @@ where
|
|||||||
|
|
||||||
impl<'a, T> Named for StdMapObserver<'a, T>
|
impl<'a, T> Named for StdMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
@ -138,7 +138,7 @@ where
|
|||||||
|
|
||||||
impl<'a, T> HasLen for StdMapObserver<'a, T>
|
impl<'a, T> HasLen for StdMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
@ -148,7 +148,7 @@ where
|
|||||||
|
|
||||||
impl<'a, T> MapObserver<T> for StdMapObserver<'a, T>
|
impl<'a, T> MapObserver<T> for StdMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn map(&self) -> Option<&[T]> {
|
fn map(&self) -> Option<&[T]> {
|
||||||
@ -178,7 +178,7 @@ where
|
|||||||
|
|
||||||
impl<'a, T> StdMapObserver<'a, T>
|
impl<'a, T> StdMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
/// Creates a new [`MapObserver`]
|
/// Creates a new [`MapObserver`]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@ -223,7 +223,7 @@ where
|
|||||||
#[allow(clippy::unsafe_derive_deserialize)]
|
#[allow(clippy::unsafe_derive_deserialize)]
|
||||||
pub struct ConstMapObserver<'a, T, const N: usize>
|
pub struct ConstMapObserver<'a, T, const N: usize>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
map: OwnedSliceMut<'a, T>,
|
map: OwnedSliceMut<'a, T>,
|
||||||
initial: T,
|
initial: T,
|
||||||
@ -232,7 +232,7 @@ where
|
|||||||
|
|
||||||
impl<'a, I, S, T, const N: usize> Observer<I, S> for ConstMapObserver<'a, T, N>
|
impl<'a, I, S, T, const N: usize> Observer<I, S> for ConstMapObserver<'a, T, N>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
Self: MapObserver<T>,
|
Self: MapObserver<T>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -243,7 +243,7 @@ where
|
|||||||
|
|
||||||
impl<'a, T, const N: usize> Named for ConstMapObserver<'a, T, N>
|
impl<'a, T, const N: usize> Named for ConstMapObserver<'a, T, N>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
@ -253,7 +253,7 @@ where
|
|||||||
|
|
||||||
impl<'a, T, const N: usize> HasLen for ConstMapObserver<'a, T, N>
|
impl<'a, T, const N: usize> HasLen for ConstMapObserver<'a, T, N>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
@ -263,7 +263,7 @@ where
|
|||||||
|
|
||||||
impl<'a, T, const N: usize> MapObserver<T> for ConstMapObserver<'a, T, N>
|
impl<'a, T, const N: usize> MapObserver<T> for ConstMapObserver<'a, T, N>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn usable_count(&self) -> usize {
|
fn usable_count(&self) -> usize {
|
||||||
@ -298,7 +298,7 @@ where
|
|||||||
|
|
||||||
impl<'a, T, const N: usize> ConstMapObserver<'a, T, N>
|
impl<'a, T, const N: usize> ConstMapObserver<'a, T, N>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
/// Creates a new [`MapObserver`]
|
/// Creates a new [`MapObserver`]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@ -344,7 +344,7 @@ where
|
|||||||
#[allow(clippy::unsafe_derive_deserialize)]
|
#[allow(clippy::unsafe_derive_deserialize)]
|
||||||
pub struct VariableMapObserver<'a, T>
|
pub struct VariableMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
map: OwnedSliceMut<'a, T>,
|
map: OwnedSliceMut<'a, T>,
|
||||||
size: OwnedRefMut<'a, usize>,
|
size: OwnedRefMut<'a, usize>,
|
||||||
@ -354,7 +354,7 @@ where
|
|||||||
|
|
||||||
impl<'a, I, S, T> Observer<I, S> for VariableMapObserver<'a, T>
|
impl<'a, I, S, T> Observer<I, S> for VariableMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
Self: MapObserver<T>,
|
Self: MapObserver<T>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -365,7 +365,7 @@ where
|
|||||||
|
|
||||||
impl<'a, T> Named for VariableMapObserver<'a, T>
|
impl<'a, T> Named for VariableMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
@ -375,7 +375,7 @@ where
|
|||||||
|
|
||||||
impl<'a, T> HasLen for VariableMapObserver<'a, T>
|
impl<'a, T> HasLen for VariableMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
@ -385,7 +385,7 @@ where
|
|||||||
|
|
||||||
impl<'a, T> MapObserver<T> for VariableMapObserver<'a, T>
|
impl<'a, T> MapObserver<T> for VariableMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn map(&self) -> Option<&[T]> {
|
fn map(&self) -> Option<&[T]> {
|
||||||
@ -420,7 +420,7 @@ where
|
|||||||
|
|
||||||
impl<'a, T> VariableMapObserver<'a, T>
|
impl<'a, T> VariableMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
/// Creates a new [`MapObserver`]
|
/// Creates a new [`MapObserver`]
|
||||||
pub fn new(name: &'static str, map: &'a mut [T], size: &'a mut usize) -> Self {
|
pub fn new(name: &'static str, map: &'a mut [T], size: &'a mut usize) -> Self {
|
||||||
@ -568,7 +568,7 @@ where
|
|||||||
#[allow(clippy::unsafe_derive_deserialize)]
|
#[allow(clippy::unsafe_derive_deserialize)]
|
||||||
pub struct MultiMapObserver<'a, T>
|
pub struct MultiMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
maps: Vec<OwnedSliceMut<'a, T>>,
|
maps: Vec<OwnedSliceMut<'a, T>>,
|
||||||
intervals: IntervalTree<usize, usize>,
|
intervals: IntervalTree<usize, usize>,
|
||||||
@ -579,7 +579,7 @@ where
|
|||||||
|
|
||||||
impl<'a, I, S, T> Observer<I, S> for MultiMapObserver<'a, T>
|
impl<'a, I, S, T> Observer<I, S> for MultiMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
Self: MapObserver<T>,
|
Self: MapObserver<T>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -590,7 +590,7 @@ where
|
|||||||
|
|
||||||
impl<'a, T> Named for MultiMapObserver<'a, T>
|
impl<'a, T> Named for MultiMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
@ -600,7 +600,7 @@ where
|
|||||||
|
|
||||||
impl<'a, T> HasLen for MultiMapObserver<'a, T>
|
impl<'a, T> HasLen for MultiMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
@ -610,7 +610,7 @@ where
|
|||||||
|
|
||||||
impl<'a, T> MapObserver<T> for MultiMapObserver<'a, T>
|
impl<'a, T> MapObserver<T> for MultiMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn map(&self) -> Option<&[T]> {
|
fn map(&self) -> Option<&[T]> {
|
||||||
@ -692,7 +692,7 @@ where
|
|||||||
|
|
||||||
impl<'a, T> MultiMapObserver<'a, T>
|
impl<'a, T> MultiMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
/// Creates a new [`MultiMapObserver`]
|
/// Creates a new [`MultiMapObserver`]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
@ -16,13 +16,13 @@ use alloc::{
|
|||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
use core::{marker::PhantomData, time::Duration};
|
use core::{marker::PhantomData, time::Duration};
|
||||||
use num::Integer;
|
use num_traits::PrimInt;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct CalibrationStage<C, E, EM, I, O, OT, S, T, Z>
|
pub struct CalibrationStage<C, E, EM, I, O, OT, S, T, Z>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
C: Corpus<I>,
|
C: Corpus<I>,
|
||||||
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
|
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
@ -42,7 +42,7 @@ const CAL_STAGE_MAX: usize = 8;
|
|||||||
impl<C, E, EM, I, O, OT, S, T, Z> Stage<E, EM, S, Z>
|
impl<C, E, EM, I, O, OT, S, T, Z> Stage<E, EM, S, Z>
|
||||||
for CalibrationStage<C, E, EM, I, O, OT, S, T, Z>
|
for CalibrationStage<C, E, EM, I, O, OT, S, T, Z>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
C: Corpus<I>,
|
C: Corpus<I>,
|
||||||
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
|
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
@ -210,7 +210,7 @@ crate::impl_serdeany!(PowerScheduleMetadata);
|
|||||||
|
|
||||||
impl<C, E, I, EM, O, OT, S, T, Z> CalibrationStage<C, E, EM, I, O, OT, S, T, Z>
|
impl<C, E, I, EM, O, OT, S, T, Z> CalibrationStage<C, E, EM, I, O, OT, S, T, Z>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
C: Corpus<I>,
|
C: Corpus<I>,
|
||||||
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
|
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use alloc::string::{String, ToString};
|
use alloc::string::{String, ToString};
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use num::Integer;
|
use num_traits::PrimInt;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::{Corpus, IsFavoredMetadata, PowerScheduleTestcaseMetaData, Testcase},
|
corpus::{Corpus, IsFavoredMetadata, PowerScheduleTestcaseMetaData, Testcase},
|
||||||
@ -34,7 +34,7 @@ const HAVOC_MAX_MULT: f64 = 64.0;
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct PowerMutationalStage<C, E, EM, I, M, O, OT, S, T, Z>
|
pub struct PowerMutationalStage<C, E, EM, I, M, O, OT, S, T, Z>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
C: Corpus<I>,
|
C: Corpus<I>,
|
||||||
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
|
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
@ -55,7 +55,7 @@ where
|
|||||||
impl<C, E, EM, I, M, O, OT, S, T, Z> MutationalStage<C, E, EM, I, M, S, Z>
|
impl<C, E, EM, I, M, O, OT, S, T, Z> MutationalStage<C, E, EM, I, M, S, Z>
|
||||||
for PowerMutationalStage<C, E, EM, I, M, O, OT, S, T, Z>
|
for PowerMutationalStage<C, E, EM, I, M, O, OT, S, T, Z>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
C: Corpus<I>,
|
C: Corpus<I>,
|
||||||
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
|
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
@ -156,7 +156,7 @@ where
|
|||||||
impl<C, E, EM, I, M, O, OT, S, T, Z> Stage<E, EM, S, Z>
|
impl<C, E, EM, I, M, O, OT, S, T, Z> Stage<E, EM, S, Z>
|
||||||
for PowerMutationalStage<C, E, EM, I, M, O, OT, S, T, Z>
|
for PowerMutationalStage<C, E, EM, I, M, O, OT, S, T, Z>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
C: Corpus<I>,
|
C: Corpus<I>,
|
||||||
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
|
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
@ -183,7 +183,7 @@ where
|
|||||||
|
|
||||||
impl<C, E, EM, I, M, O, OT, S, T, Z> PowerMutationalStage<C, E, EM, I, M, O, OT, S, T, Z>
|
impl<C, E, EM, I, M, O, OT, S, T, Z> PowerMutationalStage<C, E, EM, I, M, O, OT, S, T, Z>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
C: Corpus<I>,
|
C: Corpus<I>,
|
||||||
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
|
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
@ -19,7 +19,7 @@ libafl = { path = "../libafl", version = "0.6.1" }
|
|||||||
libafl_targets = { path = "../libafl_targets", version = "0.6.1" }
|
libafl_targets = { path = "../libafl_targets", version = "0.6.1" }
|
||||||
serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib
|
serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib
|
||||||
hashbrown = { version = "0.9", features = ["serde", "ahash-compile-time-rng"] } # A faster hashmap, nostd compatible
|
hashbrown = { version = "0.9", features = ["serde", "ahash-compile-time-rng"] } # A faster hashmap, nostd compatible
|
||||||
num = "0.4"
|
num-traits = "0.2"
|
||||||
num_enum = "0.5.1"
|
num_enum = "0.5.1"
|
||||||
goblin = "0.4.2"
|
goblin = "0.4.2"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
|
@ -6,8 +6,8 @@ use core::{
|
|||||||
mem::{size_of, transmute, MaybeUninit},
|
mem::{size_of, transmute, MaybeUninit},
|
||||||
ptr::{copy_nonoverlapping, null},
|
ptr::{copy_nonoverlapping, null},
|
||||||
};
|
};
|
||||||
use num::Num;
|
|
||||||
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||||
|
use num_traits::Num;
|
||||||
use std::{slice::from_raw_parts, str::from_utf8_unchecked};
|
use std::{slice::from_raw_parts, str::from_utf8_unchecked};
|
||||||
use strum_macros::EnumIter;
|
use strum_macros::EnumIter;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user