use crate::data::arbitrary::ArbitrarySpecs;
use arbitrary::{Result, Unstructured};
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
pub struct ByteSpecs {
pub set: ByteSet,
pub case: Case,
}
impl<'a> ArbitrarySpecs<'a> for ByteSpecs {
type Output = u8;
#[inline]
fn make_arbitrary(&self, u: &mut Unstructured<'a>) -> Result<Self::Output> {
let byte = self.set.make_arbitrary(u)?;
let cased = match self.case {
Case::Lowercase => byte.to_ascii_lowercase(),
Case::Uppercase => byte.to_ascii_uppercase(),
Case::Any => byte,
};
Ok(cased)
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
pub enum Case {
Lowercase,
Uppercase,
#[default]
Any,
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
pub enum ByteSet {
#[default]
Any,
Ascii,
AsciiGraphicOrSpace,
AsciiGraphic,
AsciiGraphicBashSafe,
NucleotidesCanonical(NucleotidesByteSet),
NucleotidesIupac(NucleotidesByteSet),
AminoAcidsCanonical(AminoAcidsByteSet),
Custom(&'static [u8]),
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct NucleotidesByteSet {
pub include_n: bool,
pub include_u: bool,
pub with_gaps: bool,
}
impl Default for NucleotidesByteSet {
#[inline]
fn default() -> Self {
Self {
include_n: true,
include_u: true,
with_gaps: true,
}
}
}
impl NucleotidesByteSet {
#[inline]
fn add_to_base_chars(self, chars: &[u8]) -> Vec<u8> {
let mut chars = chars.to_vec();
if self.include_n {
chars.extend_from_slice(b"Nn");
}
if self.include_u {
chars.extend_from_slice(b"Uu");
}
if self.with_gaps {
chars.push(b'-');
}
chars
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct AminoAcidsByteSet {
pub include_x: bool,
pub with_gaps: bool,
}
impl Default for AminoAcidsByteSet {
fn default() -> Self {
Self {
include_x: true,
with_gaps: true,
}
}
}
impl AminoAcidsByteSet {
#[inline]
fn add_to_base_chars(self, chars: &[u8]) -> Vec<u8> {
let mut chars = chars.to_vec();
if self.include_x {
chars.extend_from_slice(b"Xx");
}
if self.with_gaps {
chars.push(b'-');
}
chars
}
}
impl<'a> ArbitrarySpecs<'a> for ByteSet {
type Output = u8;
#[inline]
fn make_arbitrary(&self, u: &mut Unstructured<'a>) -> Result<Self::Output> {
match self {
ByteSet::Any => u.arbitrary(),
ByteSet::Ascii => u.int_in_range(0..=127),
ByteSet::AsciiGraphicOrSpace => u.int_in_range(b' '..=b'~'),
ByteSet::AsciiGraphic => u.int_in_range(b'!'..=b'~'),
ByteSet::AsciiGraphicBashSafe => u
.choose(b"%+,-./0123456789:@ABCDEFGHIJKLMNOPQRSTUVWXYZ^_abcdefghijklmnopqrstuvwxyz")
.copied(),
ByteSet::NucleotidesCanonical(set) => {
let chars = set.add_to_base_chars(b"ACGTacgt");
u.choose(&chars).copied()
}
ByteSet::NucleotidesIupac(set) => {
let chars = set.add_to_base_chars(b"ACGTURYSWKMBDHVacgturyswkmbdhv");
u.choose(&chars).copied()
}
ByteSet::AminoAcidsCanonical(set) => {
let chars = set.add_to_base_chars(b"ACDEFGHIKLMNPQRSTVWYacdefghiklmnpqrstvwy");
u.choose(&chars).copied()
}
ByteSet::Custom(items) => u.choose(items).copied(),
}
}
}