Trait Ensure

Source
pub trait Ensure<T, E, F, Factory>: Iterator<Item = Result<T, E>> + Sized
where F: Fn(&T) -> bool, Factory: Fn(usize, T) -> E,
{ // Provided method fn ensure( self, test: F, factory: Factory, ) -> EnsureIter<Self, T, E, F, Factory> { ... } }

Provided Methods§

Source

fn ensure(self, test: F, factory: Factory) -> EnsureIter<Self, T, E, F, Factory>

Applies a boolean test too each element, and fails the iteration if any element violates the constraint.

ensure(validation, factory) is the general validation tool, it takes a boolean test as an argument and applies it to each of the elements in the iteration. If the test returns true, the element is wrapped in Ok(element). Otherwise, factory gets called on it and the index of the error.

Values already wrapped in Result::Err are ignored.

§Examples

Basic usage:

use validiter::Ensure;
#[derive(Debug, PartialEq)]
struct Odd(usize, i32);
let mut iter = (0..=3).map(|v| Ok(v)).ensure(|i| i % 2 == 0, |i, v| Odd(i, v));
 
assert_eq!(iter.next(), Some(Ok(0)));
assert_eq!(iter.next(), Some(Err(Odd(1, 1))));
assert_eq!(iter.next(), Some(Ok(2)));
assert_eq!(iter.next(), Some(Err(Odd(3, 3))));

You might want to chain ensure validations to create a more complex test:

 enum IterError {
    Odd,
    NonPositive
 }
  
 let mut iter = (0..=3)
             .map(|v| Ok(v))
             .ensure(|i| i % 2 == 0, |_, _| IterError::Odd)
             .ensure(|i| *i > 0, |_, _| IterError::NonPositive);
 
 assert_eq!(iter.next(), Some(Err(IterError::NonPositive)));
 assert_eq!(iter.next(), Some(Err(IterError::Odd)));
 assert_eq!(iter.next(), Some(Ok(2)));
 assert_eq!(iter.next(), Some(Err(IterError::Odd)));

ensure ignores error elements:

 
let mut iter = [Err(0)]
                    .into_iter()
                    .ensure(|i| *i == 0, |_, v| v);

assert_eq!(iter.next(), Some(Err(0)));

Err(ValidErr::Invalid(element))

Examples found in repository?
examples/numeric_csv_parsing.rs (line 39)
5fn main() {
6    // In this example we will use the 'cast_errs' method to
7    // create a 'Vec<Vec<f64>>' collection, while ensuring
8    // the mathematical validity if this collection as a numerical
9    // matrix. To exercise the 'ensure' adapter, we'll force all
10    // elements to be non-negative as well
11
12    // Here we define the errors we expect to encounter in
13    // the parsing process:
14    #[derive(Debug)]
15    enum MatParseErr {
16        NotAFloat(usize, usize, ParseFloatError),
17        NoColumns(usize),
18        Negative(usize, usize, f64),
19        NoRows,
20        JaggedArray(usize, Vec<f64>, usize, usize),
21    }
22
23    // this is a CSV format str, with 2 rows and 2 columns
24    let csv = "1.2, 3.0
25                4.2, 0.5";
26
27    // we'll use iterator methods on the CSV to build an actual matrix over f64
28    let mat = csv
29        .lines()
30        .enumerate()
31        .map(|(i, line)| {
32            line.split(",")
33                .map(|s| s.trim())
34                .enumerate()
35                .map(|(j, s)| {
36                    s.parse::<f64>()
37                        .map_err(|parse_err| MatParseErr::NotAFloat(i, j, parse_err))
38                })
39                .ensure(|val| *val >= 0.0, |j, val| MatParseErr::Negative(i, j, val))
40                .at_least(1, |_| MatParseErr::NoColumns(i))
41                .collect::<Result<Vec<f64>, MatParseErr>>()
42        })
43        .at_least(1, |_| MatParseErr::NoRows)
44        .const_over(
45            |vec| vec.len(),
46            |i, vec, len, expected_len| MatParseErr::JaggedArray(i, vec, len, *expected_len),
47        )
48        .collect::<Result<Vec<_>, _>>();
49
50    match mat {
51        Ok(mat) => {
52            assert_eq!(mat, vec![vec![1.2, 3.0], vec![4.2, 0.5]]);
53            println!("{mat:?}")
54        }
55        Err(mperr) => match mperr {
56            MatParseErr::NotAFloat(i, j, err) => println!("Got {err} at pos [{i}, {j}]"),
57            MatParseErr::NoColumns(i) => {
58                println!("Row {i} is without any data, which would force the matrix to be empty")
59            }
60            MatParseErr::Negative(i, j, val) => {
61                println!("value {val} at pos [{i}, {j}] is negative")
62            }
63            MatParseErr::NoRows => println!("There are no rows in the matrix"),
64            MatParseErr::JaggedArray(i, _vec, len, expected_len) => {
65                println!("Row {i} has len {len}, when all rows should have length {expected_len}")
66            }
67        },
68    }
69}

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§

Source§

impl<I, T, E, F, Factory> Ensure<T, E, F, Factory> for I
where I: Iterator<Item = Result<T, E>>, F: Fn(&T) -> bool, Factory: Fn(usize, T) -> E,