pub trait Ensure<T, E, F, Factory>: Iterator<Item = Result<T, E>> + Sized{
// Provided method
fn ensure(
self,
test: F,
factory: Factory,
) -> EnsureIter<Self, T, E, F, Factory> { ... }
}
Provided Methods§
Sourcefn ensure(self, test: F, factory: Factory) -> EnsureIter<Self, T, E, F, Factory>
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)));
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.