diceprop 0.3.0

Mathematical properties for random testing
Documentation
use std::{
    array,
    fmt::{Debug, Write},
};

use dicetest::hint;

use crate::{Elem, Eval};

/// Represents elements that were chosen from a set and that can be used as variables in properties.
///
/// It contains `N` elements of type `S`.
#[derive(Clone, Copy)]
pub struct Vars<'a, S: Debug, const N: usize> {
    /// The name of the set the elements were chosen from.
    pub set: &'a str,
    /// The elements of the set.
    pub elems: [Elem<'a, S>; N],
}

impl<'a, S: Debug, const N: usize> Vars<'a, S, N> {
    pub fn new(set: &'a str, elems: [Elem<'a, S>; N]) -> Self {
        Self { set, elems }
    }

    /// Returns [`Eval`]s that contain the variables.
    ///
    /// This operation will log the variables via [`dicetest::hints`].
    pub fn eval(self) -> [Eval<&'a str, S>; N] {
        let set = self.set;
        let elems = self.elems;

        fn elem_names<S: Debug, const N: usize>(elems: &[Elem<S>; N]) -> String {
            let mut acc = String::new();
            for (i, elem) in elems.iter().enumerate() {
                if i == 0 {
                    write!(acc, "{}", elem.name).unwrap();
                } else {
                    write!(acc, ", {}", elem.name).unwrap();
                }
            }
            acc
        }

        hint!("{} of {}", elem_names(&elems), set);
        elems.map(|elem| elem.eval())
    }

    /// Returns a [`Vars`] with the same names and references to the original values.
    pub fn as_ref<'b: 'a>(&'b self) -> Vars<'a, &'b S, N> {
        let elems = array::from_fn(|i| self.elems[i].as_ref());
        Vars::new(self.set, elems)
    }
}