use crate::{Arbitrary, Error, Result};
use std::marker::PhantomData;
use std::{mem, ops};
pub struct Unstructured<'a> {
data: &'a [u8],
}
impl<'a> Unstructured<'a> {
pub fn new(data: &'a [u8]) -> Self {
Unstructured { data }
}
#[inline]
pub fn len(&self) -> usize {
self.data.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn arbitrary<A>(&mut self) -> Result<A>
where
A: Arbitrary,
{
<A as Arbitrary>::arbitrary(self)
}
pub fn arbitrary_len<ElementType>(&mut self) -> Result<usize>
where
ElementType: Arbitrary,
{
let byte_size = self.arbitrary_byte_size()?;
let (lower, upper) = <ElementType as Arbitrary>::size_hint(0);
let elem_size = upper.unwrap_or_else(|| lower * 2);
let elem_size = std::cmp::max(1, elem_size);
Ok(byte_size / elem_size)
}
fn arbitrary_byte_size(&mut self) -> Result<usize> {
if self.data.len() == 0 {
Err(Error::NotEnoughData)
} else if self.data.len() == 1 {
self.data = &[];
Ok(0)
} else {
let len = if self.data.len() <= std::u8::MAX as usize + 1 {
let bytes = 1;
let max_size = self.data.len() - bytes;
let (rest, for_size) = self.data.split_at(max_size);
self.data = rest;
Self::int_in_range_impl(0..=max_size as u8, for_size.iter().copied())?.0 as usize
} else if self.data.len() <= std::u16::MAX as usize + 1 {
let bytes = 2;
let max_size = self.data.len() - bytes;
let (rest, for_size) = self.data.split_at(max_size);
self.data = rest;
Self::int_in_range_impl(0..=max_size as u16, for_size.iter().copied())?.0 as usize
} else if self.data.len() <= std::u32::MAX as usize + 1 {
let bytes = 4;
let max_size = self.data.len() - bytes;
let (rest, for_size) = self.data.split_at(max_size);
self.data = rest;
Self::int_in_range_impl(0..=max_size as u32, for_size.iter().copied())?.0 as usize
} else {
let bytes = 8;
let max_size = self.data.len() - bytes;
let (rest, for_size) = self.data.split_at(max_size);
self.data = rest;
Self::int_in_range_impl(0..=max_size as u64, for_size.iter().copied())?.0 as usize
};
Ok(len)
}
}
pub fn int_in_range<T>(&mut self, range: ops::RangeInclusive<T>) -> Result<T>
where
T: Int,
{
let (result, bytes_consumed) = Self::int_in_range_impl(range, self.data.iter().cloned())?;
self.data = &self.data[bytes_consumed..];
Ok(result)
}
fn int_in_range_impl<T>(
range: ops::RangeInclusive<T>,
mut bytes: impl Iterator<Item = u8>,
) -> Result<(T, usize)>
where
T: Int,
{
let start = range.start();
let end = range.end();
assert!(
start <= end,
"`arbitrary::Unstructured::int_in_range` requires a non-empty range"
);
let range: T::Widest = end.as_widest() - start.as_widest();
let mut result = T::Widest::ZERO;
let mut offset: usize = 0;
while offset < mem::size_of::<T>()
&& (range >> T::Widest::from_usize(offset)) > T::Widest::ZERO
{
let byte = bytes.next().ok_or(Error::NotEnoughData)?;
result = (result << 8) | T::Widest::from_u8(byte);
offset += 1;
}
if let Some(range) = range.checked_add(T::Widest::ONE) {
result = result % range;
}
Ok((
T::from_widest(start.as_widest().wrapping_add(result)),
offset,
))
}
pub fn choose<'b, T>(&mut self, choices: &'b [T]) -> Result<&'b T> {
assert!(
!choices.is_empty(),
"`arbitrary::Unstructured::choose` must be given a non-empty set of choices"
);
let idx = self.int_in_range(0..=choices.len() - 1)?;
Ok(&choices[idx])
}
pub fn fill_buffer(&mut self, buffer: &mut [u8]) -> Result<()> {
let bytes = self.get_bytes(buffer.len())?;
buffer.copy_from_slice(bytes);
Ok(())
}
pub fn get_bytes(&mut self, size: usize) -> Result<&'a [u8]> {
if self.data.len() < size {
return Err(Error::NotEnoughData);
}
let (for_buf, rest) = self.data.split_at(size);
self.data = rest;
Ok(for_buf)
}
pub fn take_rest(mut self) -> &'a [u8] {
mem::replace(&mut self.data, &[])
}
pub fn arbitrary_iter<'b, ElementType: Arbitrary>(
&'b mut self,
) -> Result<ArbitraryIter<'a, 'b, ElementType>> {
let size = self.arbitrary_len::<ElementType>()?;
Ok(ArbitraryIter {
size,
u: &mut *self,
_marker: PhantomData,
})
}
pub fn arbitrary_take_rest_iter<ElementType: Arbitrary>(
self,
) -> Result<ArbitraryTakeRestIter<'a, ElementType>> {
let (lower, upper) = ElementType::size_hint(0);
let elem_size = upper.unwrap_or(lower * 2);
let elem_size = std::cmp::max(1, elem_size);
let size = self.len() / elem_size;
Ok(ArbitraryTakeRestIter {
size,
u: Some(self),
_marker: PhantomData,
})
}
}
pub struct ArbitraryIter<'a, 'b, ElementType> {
u: &'b mut Unstructured<'a>,
size: usize,
_marker: PhantomData<ElementType>,
}
impl<'a, 'b, ElementType: Arbitrary> Iterator for ArbitraryIter<'a, 'b, ElementType> {
type Item = Result<ElementType>;
fn next(&mut self) -> Option<Result<ElementType>> {
if self.size == 0 {
None
} else {
self.size -= 1;
Some(Arbitrary::arbitrary(self.u))
}
}
}
pub struct ArbitraryTakeRestIter<'a, ElementType> {
u: Option<Unstructured<'a>>,
size: usize,
_marker: PhantomData<ElementType>,
}
impl<'a, ElementType: Arbitrary> Iterator for ArbitraryTakeRestIter<'a, ElementType> {
type Item = Result<ElementType>;
fn next(&mut self) -> Option<Result<ElementType>> {
if let Some(mut u) = self.u.take() {
if self.size == 1 {
Some(Arbitrary::arbitrary_take_rest(u))
} else if self.size == 0 {
None
} else {
self.size -= 1;
let ret = Arbitrary::arbitrary(&mut u);
self.u = Some(u);
Some(ret)
}
} else {
None
}
}
}
pub trait Int:
Copy
+ PartialOrd
+ Ord
+ ops::Sub<Self, Output = Self>
+ ops::Rem<Self, Output = Self>
+ ops::Shr<Self, Output = Self>
+ ops::Shl<usize, Output = Self>
+ ops::BitOr<Self, Output = Self>
{
#[doc(hidden)]
type Widest: Int;
#[doc(hidden)]
const ZERO: Self;
#[doc(hidden)]
const ONE: Self;
#[doc(hidden)]
fn as_widest(self) -> Self::Widest;
#[doc(hidden)]
fn from_widest(w: Self::Widest) -> Self;
#[doc(hidden)]
fn from_u8(b: u8) -> Self;
#[doc(hidden)]
fn from_usize(u: usize) -> Self;
#[doc(hidden)]
fn checked_add(self, rhs: Self) -> Option<Self>;
#[doc(hidden)]
fn wrapping_add(self, rhs: Self) -> Self;
}
macro_rules! impl_int {
( $( $ty:ty : $widest:ty ; )* ) => {
$(
impl Int for $ty {
type Widest = $widest;
const ZERO: Self = 0;
const ONE: Self = 1;
fn as_widest(self) -> Self::Widest {
self as $widest
}
fn from_widest(w: Self::Widest) -> Self {
let x = <$ty>::max_value().as_widest();
(w % x) as Self
}
fn from_u8(b: u8) -> Self {
b as Self
}
fn from_usize(u: usize) -> Self {
u as Self
}
fn checked_add(self, rhs: Self) -> Option<Self> {
<$ty>::checked_add(self, rhs)
}
fn wrapping_add(self, rhs: Self) -> Self {
<$ty>::wrapping_add(self, rhs)
}
}
)*
}
}
impl_int! {
u8: u128;
u16: u128;
u32: u128;
u64: u128;
u128: u128;
usize: u128;
i8: i128;
i16: i128;
i32: i128;
i64: i128;
i128: i128;
isize: i128;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_byte_size() {
let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 6]);
assert_eq!(u.arbitrary_byte_size().unwrap(), 6);
assert_eq!(u.len(), 9);
let mut v = vec![];
v.resize(260, 0);
v.push(1);
v.push(4);
let mut u = Unstructured::new(&v);
assert_eq!(u.arbitrary_byte_size().unwrap(), 0x104);
assert_eq!(u.len(), 260);
}
#[test]
fn int_in_range_of_one() {
let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 6]);
let x = u.int_in_range(0..=0).unwrap();
assert_eq!(x, 0);
let choice = *u.choose(&[42]).unwrap();
assert_eq!(choice, 42)
}
}