use alloc::vec::Vec;
use core::{cmp::min, marker::PhantomData};
use crate::{
bolts::rands::Rand,
inputs::{bytes::BytesInput, GeneralizedInput, Input},
state::HasRand,
Error,
};
pub mod gramatron;
pub use gramatron::*;
#[cfg(feature = "nautilus")]
pub mod nautilus;
#[cfg(feature = "nautilus")]
pub use nautilus::*;
const DUMMY_BYTES_MAX: usize = 64;
pub trait Generator<I, S>
where
I: Input,
{
fn generate(&mut self, state: &mut S) -> Result<I, Error>;
fn generate_dummy(&self, state: &mut S) -> I;
}
#[derive(Clone, Debug)]
pub struct GeneralizedInputBytesGenerator<G, S> {
bytes_generator: G,
phantom: PhantomData<S>,
}
impl<G, S> GeneralizedInputBytesGenerator<G, S>
where
S: HasRand,
G: Generator<BytesInput, S>,
{
pub fn new(bytes_generator: G) -> Self {
Self {
bytes_generator,
phantom: PhantomData,
}
}
}
impl<G, S> From<G> for GeneralizedInputBytesGenerator<G, S>
where
S: HasRand,
G: Generator<BytesInput, S>,
{
fn from(bytes_generator: G) -> Self {
Self::new(bytes_generator)
}
}
impl<G, S> Generator<GeneralizedInput, S> for GeneralizedInputBytesGenerator<G, S>
where
S: HasRand,
G: Generator<BytesInput, S>,
{
fn generate(&mut self, state: &mut S) -> Result<GeneralizedInput, Error> {
Ok(self.bytes_generator.generate(state)?.into())
}
fn generate_dummy(&self, state: &mut S) -> GeneralizedInput {
self.bytes_generator.generate_dummy(state).into()
}
}
#[derive(Clone, Debug)]
pub struct RandBytesGenerator<S>
where
S: HasRand,
{
max_size: usize,
phantom: PhantomData<S>,
}
impl<S> Generator<BytesInput, S> for RandBytesGenerator<S>
where
S: HasRand,
{
fn generate(&mut self, state: &mut S) -> Result<BytesInput, Error> {
let mut size = state.rand_mut().below(self.max_size as u64);
if size == 0 {
size = 1;
}
let random_bytes: Vec<u8> = (0..size)
.map(|_| state.rand_mut().below(256) as u8)
.collect();
Ok(BytesInput::new(random_bytes))
}
fn generate_dummy(&self, _state: &mut S) -> BytesInput {
let size = min(self.max_size, DUMMY_BYTES_MAX);
BytesInput::new(vec![0; size])
}
}
impl<S> RandBytesGenerator<S>
where
S: HasRand,
{
#[must_use]
pub fn new(max_size: usize) -> Self {
Self {
max_size,
phantom: PhantomData,
}
}
}
#[derive(Clone, Debug)]
pub struct RandPrintablesGenerator<S>
where
S: HasRand,
{
max_size: usize,
phantom: PhantomData<S>,
}
impl<S> Generator<BytesInput, S> for RandPrintablesGenerator<S>
where
S: HasRand,
{
fn generate(&mut self, state: &mut S) -> Result<BytesInput, Error> {
let mut size = state.rand_mut().below(self.max_size as u64);
if size == 0 {
size = 1;
}
let printables = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz \t\n!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~".as_bytes();
let random_bytes: Vec<u8> = (0..size)
.map(|_| *state.rand_mut().choose(printables))
.collect();
Ok(BytesInput::new(random_bytes))
}
fn generate_dummy(&self, _state: &mut S) -> BytesInput {
let size = min(self.max_size, DUMMY_BYTES_MAX);
BytesInput::new(vec![0_u8; size])
}
}
impl<S> RandPrintablesGenerator<S>
where
S: HasRand,
{
#[must_use]
pub fn new(max_size: usize) -> Self {
Self {
max_size,
phantom: PhantomData,
}
}
}
#[allow(missing_docs)]
#[cfg(feature = "python")]
pub mod pybind {
use alloc::vec::Vec;
use pyo3::prelude::*;
use crate::{
generators::{Generator, RandBytesGenerator, RandPrintablesGenerator},
inputs::{BytesInput, HasBytesVec},
state::pybind::{PythonStdState, PythonStdStateWrapper},
Error,
};
#[derive(Clone, Debug)]
pub struct PyObjectGenerator {
inner: PyObject,
}
impl PyObjectGenerator {
#[must_use]
pub fn new(obj: PyObject) -> Self {
PyObjectGenerator { inner: obj }
}
}
impl Generator<BytesInput, PythonStdState> for PyObjectGenerator {
fn generate(&mut self, state: &mut PythonStdState) -> Result<BytesInput, Error> {
let bytes = Python::with_gil(|py| -> PyResult<Vec<u8>> {
self.inner
.call_method1(py, "generate", (PythonStdStateWrapper::wrap(state),))?
.extract(py)
})
.unwrap();
Ok(BytesInput::new(bytes))
}
fn generate_dummy(&self, state: &mut PythonStdState) -> BytesInput {
let bytes = Python::with_gil(|py| -> PyResult<Vec<u8>> {
self.inner
.call_method1(py, "generate_dummy", (PythonStdStateWrapper::wrap(state),))?
.extract(py)
})
.unwrap();
BytesInput::new(bytes)
}
}
#[pyclass(unsendable, name = "RandBytesGenerator")]
#[derive(Debug, Clone)]
pub struct PythonRandBytesGenerator {
pub inner: RandBytesGenerator<PythonStdState>,
}
#[pymethods]
impl PythonRandBytesGenerator {
#[new]
fn new(max_size: usize) -> Self {
Self {
inner: RandBytesGenerator::new(max_size),
}
}
fn generate(&mut self, state: &mut PythonStdStateWrapper) -> Vec<u8> {
self.inner
.generate(state.unwrap_mut())
.expect("PythonRandBytesGenerator::generate failed")
.bytes()
.to_vec()
}
fn as_generator(slf: Py<Self>) -> PythonGenerator {
PythonGenerator::new_rand_bytes(slf)
}
}
#[pyclass(unsendable, name = "RandPrintablesGenerator")]
#[derive(Debug, Clone)]
pub struct PythonRandPrintablesGenerator {
pub inner: RandPrintablesGenerator<PythonStdState>,
}
#[pymethods]
impl PythonRandPrintablesGenerator {
#[new]
fn new(max_size: usize) -> Self {
Self {
inner: RandPrintablesGenerator::new(max_size),
}
}
fn generate(&mut self, state: &mut PythonStdStateWrapper) -> Vec<u8> {
self.inner
.generate(state.unwrap_mut())
.expect("PythonRandPrintablesGenerator::generate failed")
.bytes()
.to_vec()
}
fn as_generator(slf: Py<Self>) -> PythonGenerator {
PythonGenerator::new_rand_printables(slf)
}
}
#[derive(Debug, Clone)]
enum PythonGeneratorWrapper {
RandBytes(Py<PythonRandBytesGenerator>),
RandPrintables(Py<PythonRandPrintablesGenerator>),
Python(PyObjectGenerator),
}
#[pyclass(unsendable, name = "Generator")]
#[derive(Debug, Clone)]
pub struct PythonGenerator {
wrapper: PythonGeneratorWrapper,
}
macro_rules! unwrap_me {
($wrapper:expr, $name:ident, $body:block) => {
crate::unwrap_me_body!($wrapper, $name, $body, PythonGeneratorWrapper,
{ RandBytes, RandPrintables },
{
Python(py_wrapper) => {
let $name = py_wrapper;
$body
}
}
)
};
}
macro_rules! unwrap_me_mut {
($wrapper:expr, $name:ident, $body:block) => {
crate::unwrap_me_mut_body!($wrapper, $name, $body, PythonGeneratorWrapper,
{ RandBytes, RandPrintables },
{
Python(py_wrapper) => {
let $name = py_wrapper;
$body
}
}
)
};
}
#[pymethods]
impl PythonGenerator {
#[staticmethod]
fn new_rand_bytes(py_gen: Py<PythonRandBytesGenerator>) -> Self {
Self {
wrapper: PythonGeneratorWrapper::RandBytes(py_gen),
}
}
#[staticmethod]
fn new_rand_printables(py_gen: Py<PythonRandPrintablesGenerator>) -> Self {
Self {
wrapper: PythonGeneratorWrapper::RandPrintables(py_gen),
}
}
#[staticmethod]
#[must_use]
pub fn new_py(obj: PyObject) -> Self {
Self {
wrapper: PythonGeneratorWrapper::Python(PyObjectGenerator::new(obj)),
}
}
#[must_use]
pub fn unwrap_py(&self) -> Option<PyObject> {
match &self.wrapper {
PythonGeneratorWrapper::Python(pyo) => Some(pyo.inner.clone()),
_ => None,
}
}
}
impl Generator<BytesInput, PythonStdState> for PythonGenerator {
fn generate(&mut self, state: &mut PythonStdState) -> Result<BytesInput, Error> {
unwrap_me_mut!(self.wrapper, g, { g.generate(state) })
}
fn generate_dummy(&self, state: &mut PythonStdState) -> BytesInput {
unwrap_me!(self.wrapper, g, { g.generate_dummy(state) })
}
}
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonRandBytesGenerator>()?;
m.add_class::<PythonRandPrintablesGenerator>()?;
m.add_class::<PythonGenerator>()?;
Ok(())
}
}