use crate::error::FeroxFuzzError;
use crate::std_ext::convert::{AsInner, IntoInner};
use crate::std_ext::fmt::DisplayExt;
use crate::AsBytes;
use libafl::inputs::{HasBytesVec, Input};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::fmt::{self, Debug, Display, Formatter};
use std::str::FromStr;
use std::string::ParseError;
use tracing::{error, instrument};
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Data {
Fuzzable(Vec<u8>),
Static(Vec<u8>),
}
impl AsInner for Data {
type Type = Vec<u8>;
fn inner(&self) -> &Self::Type {
match self {
Self::Fuzzable(value) | Self::Static(value) => value,
}
}
}
impl IntoInner for Data {
type Type = Vec<u8>;
#[must_use]
fn into_inner(self) -> Self::Type {
match self {
Self::Fuzzable(value) | Self::Static(value) => value,
}
}
}
impl Debug for Data {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::Fuzzable(_) => f.debug_tuple("Fuzzable").field(&self.format()).finish(),
Self::Static(_) => f.debug_tuple("Static").field(&self.format()).finish(),
}
}
}
impl Display for Data {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
write!(f, "{}", self.format())
}
}
impl Default for Data {
fn default() -> Self {
Self::Static(Vec::new())
}
}
impl Data {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn toggle_type(&mut self) {
*self = match std::mem::take(self) {
Self::Fuzzable(inner) => Self::Static(inner),
Self::Static(inner) => Self::Fuzzable(inner),
}
}
fn format(&self) -> String {
match self {
Self::Fuzzable(value) | Self::Static(value) => {
std::str::from_utf8(value).map_or_else(|_| self.display_top(3), String::from)
}
}
}
#[must_use]
pub const fn is_fuzzable(&self) -> bool {
matches!(self, Self::Fuzzable(_))
}
#[instrument(skip_all, level = "trace")]
pub fn as_str(&self) -> Result<&str, FeroxFuzzError> {
std::str::from_utf8(self.inner()).map_err(|err| {
error!(?err, "failed to convert Data to utf-8");
FeroxFuzzError::UnparsableData { source: err }
})
}
pub fn resize(&mut self, new_size: usize) {
match self {
Self::Fuzzable(inner) | Self::Static(inner) => inner.resize(new_size, 0),
}
}
#[must_use]
pub fn len(&self) -> usize {
match self {
Self::Fuzzable(inner) | Self::Static(inner) => inner.len(),
}
}
#[must_use]
pub fn is_empty(&self) -> bool {
match self {
Self::Fuzzable(inner) | Self::Static(inner) => inner.is_empty(),
}
}
#[must_use]
pub fn as_bytes_mut(&mut self) -> &mut [u8] {
match self {
Self::Fuzzable(inner) | Self::Static(inner) => inner,
}
}
}
impl FromStr for Data {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self::Static(s.as_bytes().to_vec()))
}
}
impl AsRef<[u8]> for Data {
fn as_ref(&self) -> &[u8] {
match self {
Self::Fuzzable(inner) | Self::Static(inner) => inner,
}
}
}
impl From<Vec<u8>> for Data {
fn from(value: Vec<u8>) -> Self {
Self::Static(value)
}
}
impl From<&[u8]> for Data {
fn from(value: &[u8]) -> Self {
Self::Static(value.to_owned())
}
}
impl From<String> for Data {
fn from(value: String) -> Self {
Self::Static(value.into_bytes())
}
}
impl From<&str> for Data {
fn from(value: &str) -> Self {
Self::Static(value.as_bytes().to_vec())
}
}
impl AsBytes for Data {
fn as_bytes(&self) -> &[u8] {
self.as_ref()
}
}
impl PartialEq<&Self> for Data {
fn eq(&self, other: &&Self) -> bool {
self.as_ref() == other.as_ref()
}
}
impl PartialEq<Data> for &Data {
fn eq(&self, other: &Data) -> bool {
self.as_ref() == other.as_ref()
}
}
impl PartialEq<str> for Data {
fn eq(&self, other: &str) -> bool {
self.as_ref() == other.as_bytes()
}
}
impl PartialEq<Data> for str {
fn eq(&self, other: &Data) -> bool {
self.as_bytes() == other.as_ref()
}
}
impl PartialEq<&str> for Data {
fn eq(&self, other: &&str) -> bool {
self.as_ref() == other.as_bytes()
}
}
impl PartialEq<Data> for &str {
fn eq(&self, other: &Data) -> bool {
self.as_bytes() == other.as_ref()
}
}
impl PartialEq<String> for Data {
fn eq(&self, other: &String) -> bool {
self.as_ref() == other.as_bytes()
}
}
impl PartialEq<Data> for String {
fn eq(&self, other: &Data) -> bool {
self.as_bytes() == other.as_ref()
}
}
impl PartialEq<&[u8]> for Data {
fn eq(&self, other: &&[u8]) -> bool {
&self.as_ref() == other
}
}
impl PartialEq<Data> for &[u8] {
fn eq(&self, other: &Data) -> bool {
self == &other.as_ref()
}
}
impl PartialEq<Vec<u8>> for Data {
fn eq(&self, other: &Vec<u8>) -> bool {
self.as_ref() == other
}
}
impl PartialEq<Data> for Vec<u8> {
fn eq(&self, other: &Data) -> bool {
self == other.as_ref()
}
}
impl HasBytesVec for Data {
fn bytes(&self) -> &[u8] {
self.as_ref()
}
fn bytes_mut(&mut self) -> &mut Vec<u8> {
match self {
Self::Fuzzable(inner) | Self::Static(inner) => inner,
}
}
}
impl Input for Data {
fn generate_name(&self, idx: usize) -> String {
format!("{}_{idx}", self.format())
}
}