Revision control

Copy as Markdown

Other Tools

// Copyright © 2019 The Rust Fuzz Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Wrappers around raw, unstructured bytes.
use crate::{Arbitrary, Error, Result};
use std::marker::PhantomData;
use std::ops::ControlFlow;
use std::{mem, ops};
/// A source of unstructured data.
///
/// An `Unstructured` helps `Arbitrary` implementations interpret raw data
/// (typically provided by a fuzzer) as a "DNA string" that describes how to
/// construct the `Arbitrary` type. The goal is that a small change to the "DNA
/// string" (the raw data wrapped by an `Unstructured`) results in a small
/// change to the generated `Arbitrary` instance. This helps a fuzzer
/// efficiently explore the `Arbitrary`'s input space.
///
/// `Unstructured` is deterministic: given the same raw data, the same series of
/// API calls will return the same results (modulo system resource constraints,
/// like running out of memory). However, `Unstructured` does not guarantee
/// anything beyond that: it makes not guarantee that it will yield bytes from
/// the underlying data in any particular order.
///
/// You shouldn't generally need to use an `Unstructured` unless you are writing
/// a custom `Arbitrary` implementation by hand, instead of deriving it. Mostly,
/// you should just be passing it through to nested `Arbitrary::arbitrary`
/// calls.
///
/// # Example
///
/// Imagine you were writing a color conversion crate. You might want to write
/// fuzz tests that take a random RGB color and assert various properties, run
/// functions and make sure nothing panics, etc.
///
/// Below is what translating the fuzzer's raw input into an `Unstructured` and
/// using that to generate an arbitrary RGB color might look like:
///
/// ```
/// # #[cfg(feature = "derive")] fn foo() {
/// use arbitrary::{Arbitrary, Unstructured};
///
/// /// An RGB color.
/// #[derive(Arbitrary)]
/// pub struct Rgb {
/// r: u8,
/// g: u8,
/// b: u8,
/// }
///
/// // Get the raw bytes from the fuzzer.
/// # let get_input_from_fuzzer = || &[];
/// let raw_data: &[u8] = get_input_from_fuzzer();
///
/// // Wrap it in an `Unstructured`.
/// let mut unstructured = Unstructured::new(raw_data);
///
/// // Generate an `Rgb` color and run our checks.
/// if let Ok(rgb) = Rgb::arbitrary(&mut unstructured) {
/// # let run_my_color_conversion_checks = |_| {};
/// run_my_color_conversion_checks(rgb);
/// }
/// # }
/// ```
pub struct Unstructured<'a> {
data: &'a [u8],
}
impl<'a> Unstructured<'a> {
/// Create a new `Unstructured` from the given raw data.
///
/// # Example
///
/// ```
/// use arbitrary::Unstructured;
///
/// let u = Unstructured::new(&[1, 2, 3, 4]);
/// ```
pub fn new(data: &'a [u8]) -> Self {
Unstructured { data }
}
/// Get the number of remaining bytes of underlying data that are still
/// available.
///
/// # Example
///
/// ```
/// use arbitrary::{Arbitrary, Unstructured};
///
/// let mut u = Unstructured::new(&[1, 2, 3]);
///
/// // Initially have three bytes of data.
/// assert_eq!(u.len(), 3);
///
/// // Generating a `bool` consumes one byte from the underlying data, so
/// // we are left with two bytes afterwards.
/// let _ = bool::arbitrary(&mut u);
/// assert_eq!(u.len(), 2);
/// ```
#[inline]
pub fn len(&self) -> usize {
self.data.len()
}
/// Is the underlying unstructured data exhausted?
///
/// `unstructured.is_empty()` is the same as `unstructured.len() == 0`.
///
/// # Example
///
/// ```
/// use arbitrary::{Arbitrary, Unstructured};
///
/// let mut u = Unstructured::new(&[1, 2, 3, 4]);
///
/// // Initially, we are not empty.
/// assert!(!u.is_empty());
///
/// // Generating a `u32` consumes all four bytes of the underlying data, so
/// // we become empty afterwards.
/// let _ = u32::arbitrary(&mut u);
/// assert!(u.is_empty());
/// ```
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
/// Generate an arbitrary instance of `A`.
///
/// This is simply a helper method that is equivalent to `<A as
/// Arbitrary>::arbitrary(self)`. This helper is a little bit more concise,
/// and can be used in situations where Rust's type inference will figure
/// out what `A` should be.
///
/// # Example
///
/// ```
/// # #[cfg(feature="derive")] fn foo() -> arbitrary::Result<()> {
/// use arbitrary::{Arbitrary, Unstructured};
///
/// #[derive(Arbitrary)]
/// struct MyType {
/// // ...
/// }
///
/// fn do_stuff(value: MyType) {
/// # let _ = value;
/// // ...
/// }
///
/// let mut u = Unstructured::new(&[1, 2, 3, 4]);
///
/// // Rust's type inference can figure out that `value` should be of type
/// // `MyType` here:
/// let value = u.arbitrary()?;
/// do_stuff(value);
/// # Ok(()) }
/// ```
pub fn arbitrary<A>(&mut self) -> Result<A>
where
A: Arbitrary<'a>,
{
<A as Arbitrary<'a>>::arbitrary(self)
}
/// Get the number of elements to insert when building up a collection of
/// arbitrary `ElementType`s.
///
/// This uses the [`<ElementType as
/// Arbitrary>::size_hint`][crate::Arbitrary::size_hint] method to smartly
/// choose a length such that we most likely have enough underlying bytes to
/// construct that many arbitrary `ElementType`s.
///
/// This should only be called within an `Arbitrary` implementation.
///
/// # Example
///
/// ```
/// use arbitrary::{Arbitrary, Result, Unstructured};
/// # pub struct MyCollection<T> { _t: std::marker::PhantomData<T> }
/// # impl<T> MyCollection<T> {
/// # pub fn with_capacity(capacity: usize) -> Self { MyCollection { _t: std::marker::PhantomData } }
/// # pub fn insert(&mut self, element: T) {}
/// # }
///
/// impl<'a, T> Arbitrary<'a> for MyCollection<T>
/// where
/// T: Arbitrary<'a>,
/// {
/// fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
/// // Get the number of `T`s we should insert into our collection.
/// let len = u.arbitrary_len::<T>()?;
///
/// // And then create a collection of that length!
/// let mut my_collection = MyCollection::with_capacity(len);
/// for _ in 0..len {
/// let element = T::arbitrary(u)?;
/// my_collection.insert(element);
/// }
///
/// Ok(my_collection)
/// }
/// }
/// ```
pub fn arbitrary_len<ElementType>(&mut self) -> Result<usize>
where
ElementType: Arbitrary<'a>,
{
let byte_size = self.arbitrary_byte_size()?;
let (lower, upper) = <ElementType as Arbitrary>::size_hint(0);
let elem_size = upper.unwrap_or(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.is_empty() {
Ok(0)
} else if self.data.len() == 1 {
self.data = &[];
Ok(0)
} else {
// Take lengths from the end of the data, since the `libFuzzer` folks
// found that this lets fuzzers more efficiently explore the input
// space.
//
// We only consume as many bytes as necessary to cover the entire
// range of the byte string.
// Note: We cast to u64 so we don't overflow when checking std::u32::MAX + 4 on 32-bit archs
let len = if self.data.len() as u64 <= std::u8::MAX as u64 + 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() as u64 <= std::u16::MAX as u64 + 2 {
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() as u64 <= std::u32::MAX as u64 + 4 {
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)
}
}
/// Generate an integer within the given range.
///
/// Do not use this to generate the size of a collection. Use
/// `arbitrary_len` instead.
///
/// # Panics
///
/// Panics if `range.start > range.end`. That is, the given range must be
/// non-empty.
///
/// # Example
///
/// ```
/// use arbitrary::{Arbitrary, Unstructured};
///
/// let mut u = Unstructured::new(&[1, 2, 3, 4]);
///
/// let x: i32 = u.int_in_range(-5_000..=-1_000)
/// .expect("constructed `u` with enough bytes to generate an `i32`");
///
/// assert!(-5_000 <= x);
/// assert!(x <= -1_000);
/// ```
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"
);
// When there is only one possible choice, don't waste any entropy from
// the underlying data.
if start == end {
return Ok((start, 0));
}
// From here on out we work with the unsigned representation. All of the
// operations performed below work out just as well whether or not `T`
// is a signed or unsigned integer.
let start = start.to_unsigned();
let end = end.to_unsigned();
let delta = end.wrapping_sub(start);
debug_assert_ne!(delta, T::Unsigned::ZERO);
// Compute an arbitrary integer offset from the start of the range. We
// do this by consuming `size_of(T)` bytes from the input to create an
// arbitrary integer and then clamping that int into our range bounds
// with a modulo operation.
let mut arbitrary_int = T::Unsigned::ZERO;
let mut bytes_consumed: usize = 0;
while (bytes_consumed < mem::size_of::<T>())
&& (delta >> T::Unsigned::from_usize(bytes_consumed * 8)) > T::Unsigned::ZERO
{
let byte = match bytes.next() {
None => break,
Some(b) => b,
};
bytes_consumed += 1;
// Combine this byte into our arbitrary integer, but avoid
// overflowing the shift for `u8` and `i8`.
arbitrary_int = if mem::size_of::<T>() == 1 {
T::Unsigned::from_u8(byte)
} else {
(arbitrary_int << 8) | T::Unsigned::from_u8(byte)
};
}
let offset = if delta == T::Unsigned::MAX {
arbitrary_int
} else {
arbitrary_int % (delta.checked_add(T::Unsigned::ONE).unwrap())
};
// Finally, we add `start` to our offset from `start` to get the result
// actual value within the range.
let result = start.wrapping_add(offset);
// And convert back to our maybe-signed representation.
let result = T::from_unsigned(result);
debug_assert!(*range.start() <= result);
debug_assert!(result <= *range.end());
Ok((result, bytes_consumed))
}
/// Choose one of the given choices.
///
/// This should only be used inside of `Arbitrary` implementations.
///
/// Returns an error if there is not enough underlying data to make a
/// choice or if no choices are provided.
///
/// # Examples
///
/// Selecting from an array of choices:
///
/// ```
/// use arbitrary::Unstructured;
///
/// let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]);
/// let choices = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
///
/// let choice = u.choose(&choices).unwrap();
///
/// println!("chose {}", choice);
/// ```
///
/// An error is returned if no choices are provided:
///
/// ```
/// use arbitrary::Unstructured;
///
/// let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]);
/// let choices: [char; 0] = [];
///
/// let result = u.choose(&choices);
///
/// assert!(result.is_err());
/// ```
pub fn choose<'b, T>(&mut self, choices: &'b [T]) -> Result<&'b T> {
let idx = self.choose_index(choices.len())?;
Ok(&choices[idx])
}
/// Choose a value in `0..len`.
///
/// Returns an error if the `len` is zero.
///
/// # Examples
///
/// Using Fisher–Yates shuffle shuffle to gerate an arbitrary permutation.
///
///
/// ```
/// use arbitrary::Unstructured;
///
/// let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]);
/// let mut permutation = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
/// let mut to_permute = &mut permutation[..];
/// while to_permute.len() > 1 {
/// let idx = u.choose_index(to_permute.len()).unwrap();
/// to_permute.swap(0, idx);
/// to_permute = &mut to_permute[1..];
/// }
///
/// println!("permutation: {:?}", permutation);
/// ```
///
/// An error is returned if the length is zero:
///
/// ```
/// use arbitrary::Unstructured;
///
/// let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]);
/// let array: [i32; 0] = [];
///
/// let result = u.choose_index(array.len());
///
/// assert!(result.is_err());
/// ```
pub fn choose_index(&mut self, len: usize) -> Result<usize> {
if len == 0 {
return Err(Error::EmptyChoose);
}
let idx = self.int_in_range(0..=len - 1)?;
Ok(idx)
}
/// Generate a boolean according to the given ratio.
///
/// # Panics
///
/// Panics when the numerator and denominator do not meet these constraints:
///
/// * `0 < numerator <= denominator`
///
/// # Example
///
/// Generate a boolean that is `true` five sevenths of the time:
///
/// ```
/// # fn foo() -> arbitrary::Result<()> {
/// use arbitrary::Unstructured;
///
/// # let my_data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
/// let mut u = Unstructured::new(&my_data);
///
/// if u.ratio(5, 7)? {
/// // Take this branch 5/7 of the time.
/// }
/// # Ok(())
/// # }
/// ```
pub fn ratio<T>(&mut self, numerator: T, denominator: T) -> Result<bool>
where
T: Int,
{
assert!(T::ZERO < numerator);
assert!(numerator <= denominator);
let x = self.int_in_range(T::ONE..=denominator)?;
Ok(x <= numerator)
}
/// Fill a `buffer` with bytes from the underlying raw data.
///
/// This should only be called within an `Arbitrary` implementation. This is
/// a very low-level operation. You should generally prefer calling nested
/// `Arbitrary` implementations like `<Vec<u8>>::arbitrary` and
/// `String::arbitrary` over using this method directly.
///
/// If this `Unstructured` does not have enough underlying data to fill the
/// whole `buffer`, it pads the buffer out with zeros.
///
/// # Example
///
/// ```
/// use arbitrary::Unstructured;
///
/// let mut u = Unstructured::new(&[1, 2, 3, 4]);
///
/// let mut buf = [0; 2];
///
/// assert!(u.fill_buffer(&mut buf).is_ok());
/// assert_eq!(buf, [1, 2]);
///
/// assert!(u.fill_buffer(&mut buf).is_ok());
/// assert_eq!(buf, [3, 4]);
///
/// assert!(u.fill_buffer(&mut buf).is_ok());
/// assert_eq!(buf, [0, 0]);
/// ```
pub fn fill_buffer(&mut self, buffer: &mut [u8]) -> Result<()> {
let n = std::cmp::min(buffer.len(), self.data.len());
buffer[..n].copy_from_slice(&self.data[..n]);
for byte in buffer[n..].iter_mut() {
*byte = 0;
}
self.data = &self.data[n..];
Ok(())
}
/// Provide `size` bytes from the underlying raw data.
///
/// This should only be called within an `Arbitrary` implementation. This is
/// a very low-level operation. You should generally prefer calling nested
/// `Arbitrary` implementations like `<Vec<u8>>::arbitrary` and
/// `String::arbitrary` over using this method directly.
///
/// # Example
///
/// ```
/// use arbitrary::Unstructured;
///
/// let mut u = Unstructured::new(&[1, 2, 3, 4]);
///
/// assert!(u.bytes(2).unwrap() == &[1, 2]);
/// assert!(u.bytes(2).unwrap() == &[3, 4]);
/// ```
pub fn 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)
}
/// Peek at `size` number of bytes of the underlying raw input.
///
/// Does not consume the bytes, only peeks at them.
///
/// Returns `None` if there are not `size` bytes left in the underlying raw
/// input.
///
/// # Example
///
/// ```
/// use arbitrary::Unstructured;
///
/// let u = Unstructured::new(&[1, 2, 3]);
///
/// assert_eq!(u.peek_bytes(0).unwrap(), []);
/// assert_eq!(u.peek_bytes(1).unwrap(), [1]);
/// assert_eq!(u.peek_bytes(2).unwrap(), [1, 2]);
/// assert_eq!(u.peek_bytes(3).unwrap(), [1, 2, 3]);
///
/// assert!(u.peek_bytes(4).is_none());
/// ```
pub fn peek_bytes(&self, size: usize) -> Option<&'a [u8]> {
self.data.get(..size)
}
/// Consume all of the rest of the remaining underlying bytes.
///
/// Returns a slice of all the remaining, unconsumed bytes.
///
/// # Example
///
/// ```
/// use arbitrary::Unstructured;
///
/// let mut u = Unstructured::new(&[1, 2, 3]);
///
/// let mut remaining = u.take_rest();
///
/// assert_eq!(remaining, [1, 2, 3]);
/// ```
pub fn take_rest(mut self) -> &'a [u8] {
mem::take(&mut self.data)
}
/// Provide an iterator over elements for constructing a collection
///
/// This is useful for implementing [`Arbitrary::arbitrary`] on collections
/// since the implementation is simply `u.arbitrary_iter()?.collect()`
pub fn arbitrary_iter<'b, ElementType: Arbitrary<'a>>(
&'b mut self,
) -> Result<ArbitraryIter<'a, 'b, ElementType>> {
Ok(ArbitraryIter {
u: &mut *self,
_marker: PhantomData,
})
}
/// Provide an iterator over elements for constructing a collection from
/// all the remaining bytes.
///
/// This is useful for implementing [`Arbitrary::arbitrary_take_rest`] on collections
/// since the implementation is simply `u.arbitrary_take_rest_iter()?.collect()`
pub fn arbitrary_take_rest_iter<ElementType: Arbitrary<'a>>(
self,
) -> Result<ArbitraryTakeRestIter<'a, ElementType>> {
Ok(ArbitraryTakeRestIter {
u: self,
_marker: PhantomData,
})
}
/// Call the given function an arbitrary number of times.
///
/// The function is given this `Unstructured` so that it can continue to
/// generate arbitrary data and structures.
///
/// You may optionaly specify minimum and maximum bounds on the number of
/// times the function is called.
///
/// You may break out of the loop early by returning
/// `Ok(std::ops::ControlFlow::Break)`. To continue the loop, return
/// `Ok(std::ops::ControlFlow::Continue)`.
///
/// # Panics
///
/// Panics if `min > max`.
///
/// # Example
///
/// Call a closure that generates an arbitrary type inside a context an
/// arbitrary number of times:
///
/// ```
/// use arbitrary::{Result, Unstructured};
/// use std::ops::ControlFlow;
///
/// enum Type {
/// /// A boolean type.
/// Bool,
///
/// /// An integer type.
/// Int,
///
/// /// A list of the `i`th type in this type's context.
/// List(usize),
/// }
///
/// fn arbitrary_types_context(u: &mut Unstructured) -> Result<Vec<Type>> {
/// let mut context = vec![];
///
/// u.arbitrary_loop(Some(10), Some(20), |u| {
/// let num_choices = if context.is_empty() {
/// 2
/// } else {
/// 3
/// };
/// let ty = match u.int_in_range::<u8>(1..=num_choices)? {
/// 1 => Type::Bool,
/// 2 => Type::Int,
/// 3 => Type::List(u.int_in_range(0..=context.len() - 1)?),
/// _ => unreachable!(),
/// };
/// context.push(ty);
/// Ok(ControlFlow::Continue(()))
/// })?;
///
/// // The number of loop iterations are constrained by the min/max
/// // bounds that we provided.
/// assert!(context.len() >= 10);
/// assert!(context.len() <= 20);
///
/// Ok(context)
/// }
/// ```
pub fn arbitrary_loop(
&mut self,
min: Option<u32>,
max: Option<u32>,
mut f: impl FnMut(&mut Self) -> Result<ControlFlow<(), ()>>,
) -> Result<()> {
let min = min.unwrap_or(0);
let max = max.unwrap_or(u32::MAX);
for _ in 0..self.int_in_range(min..=max)? {
match f(self)? {
ControlFlow::Continue(_) => continue,
ControlFlow::Break(_) => break,
}
}
Ok(())
}
}
/// Utility iterator produced by [`Unstructured::arbitrary_iter`]
pub struct ArbitraryIter<'a, 'b, ElementType> {
u: &'b mut Unstructured<'a>,
_marker: PhantomData<ElementType>,
}
impl<'a, 'b, ElementType: Arbitrary<'a>> Iterator for ArbitraryIter<'a, 'b, ElementType> {
type Item = Result<ElementType>;
fn next(&mut self) -> Option<Result<ElementType>> {
let keep_going = self.u.arbitrary().unwrap_or(false);
if keep_going {
Some(Arbitrary::arbitrary(self.u))
} else {
None
}
}
}
/// Utility iterator produced by [`Unstructured::arbitrary_take_rest_iter`]
pub struct ArbitraryTakeRestIter<'a, ElementType> {
u: Unstructured<'a>,
_marker: PhantomData<ElementType>,
}
impl<'a, ElementType: Arbitrary<'a>> Iterator for ArbitraryTakeRestIter<'a, ElementType> {
type Item = Result<ElementType>;
fn next(&mut self) -> Option<Result<ElementType>> {
let keep_going = self.u.arbitrary().unwrap_or(false);
if keep_going {
Some(Arbitrary::arbitrary(&mut self.u))
} else {
None
}
}
}
/// A trait that is implemented for all of the primitive integers:
///
/// * `u8`
/// * `u16`
/// * `u32`
/// * `u64`
/// * `u128`
/// * `usize`
/// * `i8`
/// * `i16`
/// * `i32`
/// * `i64`
/// * `i128`
/// * `isize`
///
/// Don't implement this trait yourself.
pub trait Int:
Copy
+ std::fmt::Debug
+ 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 Unsigned: Int;
#[doc(hidden)]
const ZERO: Self;
#[doc(hidden)]
const ONE: Self;
#[doc(hidden)]
const MAX: 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;
#[doc(hidden)]
fn wrapping_sub(self, rhs: Self) -> Self;
#[doc(hidden)]
fn to_unsigned(self) -> Self::Unsigned;
#[doc(hidden)]
fn from_unsigned(unsigned: Self::Unsigned) -> Self;
}
macro_rules! impl_int {
( $( $ty:ty : $unsigned_ty: ty ; )* ) => {
$(
impl Int for $ty {
type Unsigned = $unsigned_ty;
const ZERO: Self = 0;
const ONE: Self = 1;
const MAX: Self = Self::MAX;
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)
}
fn wrapping_sub(self, rhs: Self) -> Self {
<$ty>::wrapping_sub(self, rhs)
}
fn to_unsigned(self) -> Self::Unsigned {
self as $unsigned_ty
}
fn from_unsigned(unsigned: $unsigned_ty) -> Self {
unsigned as Self
}
}
)*
}
}
impl_int! {
u8: u8;
u16: u16;
u32: u32;
u64: u64;
u128: u128;
usize: usize;
i8: u8;
i16: u16;
i32: u32;
i64: u64;
i128: u128;
isize: usize;
}
#[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]);
// Should take one byte off the end
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);
// Should read two bytes off the end
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)
}
#[test]
fn int_in_range_uses_minimal_amount_of_bytes() {
let mut u = Unstructured::new(&[1, 2]);
assert_eq!(1, u.int_in_range::<u8>(0..=u8::MAX).unwrap());
assert_eq!(u.len(), 1);
let mut u = Unstructured::new(&[1, 2]);
assert_eq!(1, u.int_in_range::<u32>(0..=u8::MAX as u32).unwrap());
assert_eq!(u.len(), 1);
let mut u = Unstructured::new(&[1]);
assert_eq!(1, u.int_in_range::<u32>(0..=u8::MAX as u32 + 1).unwrap());
assert!(u.is_empty());
}
#[test]
fn int_in_range_in_bounds() {
for input in u8::MIN..=u8::MAX {
let input = [input];
let mut u = Unstructured::new(&input);
let x = u.int_in_range(1..=u8::MAX).unwrap();
assert_ne!(x, 0);
let mut u = Unstructured::new(&input);
let x = u.int_in_range(0..=u8::MAX - 1).unwrap();
assert_ne!(x, u8::MAX);
}
}
#[test]
fn int_in_range_covers_unsigned_range() {
// Test that we generate all values within the range given to
// `int_in_range`.
let mut full = [false; u8::MAX as usize + 1];
let mut no_zero = [false; u8::MAX as usize];
let mut no_max = [false; u8::MAX as usize];
let mut narrow = [false; 10];
for input in u8::MIN..=u8::MAX {
let input = [input];
let mut u = Unstructured::new(&input);
let x = u.int_in_range(0..=u8::MAX).unwrap();
full[x as usize] = true;
let mut u = Unstructured::new(&input);
let x = u.int_in_range(1..=u8::MAX).unwrap();
no_zero[x as usize - 1] = true;
let mut u = Unstructured::new(&input);
let x = u.int_in_range(0..=u8::MAX - 1).unwrap();
no_max[x as usize] = true;
let mut u = Unstructured::new(&input);
let x = u.int_in_range(100..=109).unwrap();
narrow[x as usize - 100] = true;
}
for (i, covered) in full.iter().enumerate() {
assert!(covered, "full[{}] should have been generated", i);
}
for (i, covered) in no_zero.iter().enumerate() {
assert!(covered, "no_zero[{}] should have been generated", i);
}
for (i, covered) in no_max.iter().enumerate() {
assert!(covered, "no_max[{}] should have been generated", i);
}
for (i, covered) in narrow.iter().enumerate() {
assert!(covered, "narrow[{}] should have been generated", i);
}
}
#[test]
fn int_in_range_covers_signed_range() {
// Test that we generate all values within the range given to
// `int_in_range`.
let mut full = [false; u8::MAX as usize + 1];
let mut no_min = [false; u8::MAX as usize];
let mut no_max = [false; u8::MAX as usize];
let mut narrow = [false; 21];
let abs_i8_min: isize = 128;
for input in 0..=u8::MAX {
let input = [input];
let mut u = Unstructured::new(&input);
let x = u.int_in_range(i8::MIN..=i8::MAX).unwrap();
full[(x as isize + abs_i8_min) as usize] = true;
let mut u = Unstructured::new(&input);
let x = u.int_in_range(i8::MIN + 1..=i8::MAX).unwrap();
no_min[(x as isize + abs_i8_min - 1) as usize] = true;
let mut u = Unstructured::new(&input);
let x = u.int_in_range(i8::MIN..=i8::MAX - 1).unwrap();
no_max[(x as isize + abs_i8_min) as usize] = true;
let mut u = Unstructured::new(&input);
let x = u.int_in_range(-10..=10).unwrap();
narrow[(x as isize + 10) as usize] = true;
}
for (i, covered) in full.iter().enumerate() {
assert!(covered, "full[{}] should have been generated", i);
}
for (i, covered) in no_min.iter().enumerate() {
assert!(covered, "no_min[{}] should have been generated", i);
}
for (i, covered) in no_max.iter().enumerate() {
assert!(covered, "no_max[{}] should have been generated", i);
}
for (i, covered) in narrow.iter().enumerate() {
assert!(covered, "narrow[{}] should have been generated", i);
}
}
}