eml-codec 0.4.0

Email enCOder DECoder in Rust. Support Internet Message Format and MIME (RFC 822, 5322, 2045, 2046, 2047, 2048, 2049, 6532).
Documentation
use crate::text::ascii;
use arbitrary::{Arbitrary, Result, Unstructured};

pub fn arbitrary_vec_where<'a, F, T>(u: &mut Unstructured<'a>, pred: F) -> Result<Vec<T>>
where
    F: for<'b> Fn(&'b T) -> bool,
    T: Arbitrary<'a>,
{
    let len = u.arbitrary_len::<T>()?;
    let mut v = Vec::with_capacity(len);
    for _ in 0..len {
        let x: T = u.arbitrary()?;
        if pred(&x) {
            v.push(x)
        } else {
            return Err(arbitrary::Error::IncorrectFormat);
        }
    }
    Ok(v)
}

pub fn arbitrary_vec_nonempty_where<'a, F, T>(
    u: &mut Unstructured<'a>,
    pred: F,
    default: T,
) -> Result<Vec<T>>
where
    F: for<'b> Fn(&'b T) -> bool,
    T: Arbitrary<'a>,
{
    let mut v = arbitrary_vec_where(u, pred)?;
    if v.is_empty() {
        v.push(default)
    }
    Ok(v)
}

pub fn arbitrary_vec_nonempty<'a, T>(u: &mut Unstructured<'a>) -> Result<Vec<T>>
where
    T: Arbitrary<'a>,
{
    let (mut v, last): (Vec<T>, T) = u.arbitrary()?;
    v.push(last);
    Ok(v)
}

pub fn arbitrary_string_where<'a, F>(u: &mut Unstructured<'a>, pred: F) -> Result<String>
where
    F: Fn(char) -> bool,
{
    let len = u.arbitrary_len::<char>()?;
    let mut s = String::with_capacity(len);
    for _ in 0..len {
        let c: char = u.arbitrary()?;
        if pred(c) {
            s.push(c)
        } else {
            return Err(arbitrary::Error::IncorrectFormat);
        }
    }
    Ok(s)
}

pub fn arbitrary_string_nonempty_where<'a, F>(
    u: &mut Unstructured<'a>,
    pred: F,
    default: char,
) -> Result<String>
where
    F: Fn(char) -> bool,
{
    let mut v = arbitrary_string_where(u, pred)?;
    if v.is_empty() {
        v.push(default)
    }
    Ok(v)
}

pub fn arbitrary_whitespace_nonempty(u: &mut Unstructured) -> Result<String> {
    let mut s = String::new();
    for _ in 0..=u.arbitrary_len::<u8>()? {
        let b: bool = u.arbitrary()?;
        s.push((if b { ascii::SP } else { ascii::HT }).into());
    }
    Ok(s)
}

pub fn arbitrary_shuffle<T>(u: &mut Unstructured, v: &mut [T]) -> Result<()> {
    let mut to_permute = &mut v[..];
    while to_permute.len() > 1 {
        let idx = u.choose_index(to_permute.len())?;
        to_permute.swap(0, idx);
        to_permute = &mut to_permute[1..];
    }
    Ok(())
}

pub fn arbitrary_part_body(u: &mut Unstructured) -> Result<Vec<u8>> {
    // XXX one or two final \r may get eaten by the best-effort parsing strategy...
    // (see also the comment in the test `test_multipart_cr` in part/composite.rs)
    // as a workaround, avoid this case for now...
    let mut body: Vec<_> = u.arbitrary()?;
    if let Some(b'\r') = body.last() {
        body.push(b'X')
    }
    Ok(body)
}