blob: 8fbf5a6c489bcc13ef2715dcfdf238fa04db3bd4 [file] [edit]
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
pub mod arbitrary;
pub mod containers;
pub mod range;
pub mod tuple_of;
pub mod utility;
use ::serde::de::DeserializeOwned;
use ::serde::Serialize;
use anyhow;
use anyhow::Context;
use std::any::Any;
pub trait CloneAny: Any {
fn clone_box(&self) -> Box<dyn CloneAny>;
fn as_any(&self) -> &dyn Any;
fn as_mut_any(&mut self) -> &mut dyn Any;
}
impl dyn CloneAny {
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
self.as_any().downcast_ref::<T>()
}
pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
self.as_mut_any().downcast_mut::<T>()
}
}
impl<T: Any + Clone> CloneAny for T {
fn clone_box(&self) -> Box<dyn CloneAny> {
if let Some(boxed) = self.as_any().downcast_ref::<Box<dyn CloneAny>>() {
return (**boxed).clone_box();
}
Box::new(self.clone())
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_mut_any(&mut self) -> &mut dyn Any {
self
}
}
impl Clone for Box<dyn CloneAny> {
fn clone(&self) -> Self {
self.clone_box()
}
}
/// Type alias for a type-erased corpus value.
pub type GenericCorpusValue = Box<dyn CloneAny>;
/// Type alias for a type-erased user value.
pub type GenericUserValue = Box<dyn CloneAny>;
pub trait Domain: 'static {
/// The user-facing type representing values in this domain.
type UserValue<'user>;
/// The type representing the value stored in the corpus for this domain.
type CorpusValue: Serialize + DeserializeOwned + Clone;
/// Produces a new initial `CorpusValue` for this domain.
fn init(&mut self, rng: &mut dyn rand::Rng) -> anyhow::Result<Self::CorpusValue>;
/// Mutates the given `corpus_value` in place.
fn mutate(
&mut self,
corpus_value: &mut Self::CorpusValue,
rng: &mut dyn rand::Rng,
only_shrink: bool,
) -> anyhow::Result<()>;
/// Obtains a `UserValue` from a `corpus_value`.
fn get_user_value<'a>(
&self,
corpus_value: &'a Self::CorpusValue,
) -> anyhow::Result<Self::UserValue<'a>>;
/// Deserializes a `CorpusValue` from a byte slice.
fn parse_corpus(&self, data: &[u8]) -> anyhow::Result<Self::CorpusValue> {
postcard::from_bytes(data).context("Failed to deserialize corpus value from bytes")
}
/// Serializes `corpus_value` to a Vec of bytes (ie, Vec<u8>).
fn serialize_corpus(&self, corpus_value: &Self::CorpusValue) -> anyhow::Result<Vec<u8>> {
postcard::to_stdvec(corpus_value).context("Failed to serialize corpus value to bytes")
}
/// Converts a user value to a corpus value.
#[allow(clippy::wrong_self_convention)]
fn from_value(&self, value: Self::UserValue<'_>) -> anyhow::Result<Self::CorpusValue>;
/// Validates that a corpus value satisfies the domain's constraints.
fn validate_corpus_value(&self, _corpus_value: &Self::CorpusValue) -> anyhow::Result<()> {
Ok(())
}
}
pub trait GenericDomain {
fn init(&mut self, rng: &mut dyn rand::Rng) -> anyhow::Result<GenericCorpusValue>;
fn mutate(
&mut self,
val: &mut GenericCorpusValue,
rng: &mut dyn rand::Rng,
only_shrink: bool,
) -> anyhow::Result<()>;
fn parse_corpus(&self, data: &[u8]) -> anyhow::Result<GenericCorpusValue>;
fn serialize_corpus(&self, val: &GenericCorpusValue) -> anyhow::Result<Vec<u8>>;
}
impl<D> GenericDomain for D
where
D: Domain,
D::CorpusValue: 'static,
{
fn init(&mut self, rng: &mut dyn rand::Rng) -> anyhow::Result<GenericCorpusValue> {
Ok(Box::new(self.init(rng)?))
}
fn mutate(
&mut self,
val: &mut GenericCorpusValue,
rng: &mut dyn rand::Rng,
only_shrink: bool,
) -> anyhow::Result<()> {
self.mutate(
val.downcast_mut().context("Failed to retrieve the Corpus Value")?,
rng,
only_shrink,
)
}
fn parse_corpus(&self, data: &[u8]) -> anyhow::Result<GenericCorpusValue> {
Ok(Box::new(self.parse_corpus(data)?))
}
fn serialize_corpus(&self, val: &GenericCorpusValue) -> anyhow::Result<Vec<u8>> {
self.serialize_corpus(val.downcast_ref().context("Failed to retrieve the Corpus Value")?)
}
}