validiter 0.1.1

Iterator adapters for validating iterations
Documentation
Are you a rusty little thing?

Do you want to write 10,000-line functions and just chain iterators forever? 

Do you like to watch the compiler cry while it's trying to figure out WTF is a `Fold<Map<Filter<TakeWhile<Map<StepBy<Zip<SkipWhile...`

Do you get insecure about your ugly, disgusting, _imperative_ code when you're next to Haskellers?

Introducing...
# validiter


`validiter` is meant to provide a nice rusty api for performing validations on iterators. Here is a very simple example for an adapter it provides:
```
(0..10).validate().at_most(7) // wraps the first 7 elements in Ok(i32) and the rest in a Err(ValidErr::TooMany(i32))
```

Unfortunately, our beautiful and pure functions are often fouled by unsanitized data. So how can we allow data preprocessing to be integrated into a large, LAZY iterator chain? This is where validiter comes to help.
All in all, this crate is pretty simple - take an iterator, and declare that you want to validate it. There are 2 ways to do so:
1. Import `validiter::Unvalidatable` to your scope, and call `validate()` on said iterator - you can now call all of the `ValidIter` type adapters.
2. A little more scuffed, but also valid - if your iterator is already yielding results, you can map them to `ValidIter::ValidErr<the-type-you-want>::Mapped`,
   then import `validiter::ErrLiftable` into your scope and call `lift_errs` on the iterator - this too will allow you to call `ValidIter` methods.

We have examples for both of these methods. We'll start with a simple one, using the `validate` method (this is `multi_validated_iterator` in the `examples` folder):
```
use validiter::{Unvalidatable, ValidIter};

fn main() {
    // This is the standard way to use validiter - call validate on
    // some 'Unvalidatable' iterator, and then place restrictions
    // on the iteration. Notice that 'ValidErr' type errors are always
    // ignored by validiter adapters, so the order of validation
    // placement matters, if the iteration fails - there might be 
    // ignored errors, on elements that already failed a different
    // validation.
    (0..10)
        .validate()
        .at_most(7)
        .between(2, 8)
        .ensure(|i| i % 2 == 0)
        .at_least(4)
        .for_each(|v| println!("{:?}", v));
}
```
The second example is a bit more involved, using the `lift_errs` method (`numeric_csv_parsing` in the `examples` folder):
```
use validiter::{ErrLiftable, ValidErr, ValidIter};

fn main() {
    // In this example we will use the 'lift_errs' method to
    // create a 'Vec<Vec<f64>>' collection, while ensuring 
    // the mathematical validity if this collection as a numerical
    // matrix. We will also force the matrix to be non-negative,
    // just for funsies.

    // this is a CSV format str, with 2 rows and 2 columns
    let csv = "1.2, 3.0
                4.2, 0.5";

    // we'll use iterator methods on the CSV to build an actual 
    // split the csv by rows/lines
    let mat = csv        .lines()
        // convert each row to a matrix row
        .map(
            |line| {
                // split by elements
                line.split(",")
                    // map the elements to f64 values
                    .map(|s| s.trim())
                    // if we get a parse error, we want to map it to our own error types - ValidErr<f64>
                    .map(|s| s.parse::<f64>().map_err(|_| ValidErr::<f64>::Mapped))
                    // because 'Map' is not a 'ValidIter', we need to convert the underlying data structure type
                    .lift_errs() // the iterator is over VResult<f64>, but map is not a ValidIter!
                    // force non-empty rows
                    .at_least(1)
                    // simple 'greater than 0' validation
                    .ensure(|f| *f >= 0.0)
                    // collecting each row to a vector, but now Ok Type is a vector, but Err Type is f64!
                    .collect::<Result<Vec<f64>, ValidErr<f64>>>()
            },
        )
        // we use lift_errs again to fix the typing issues
        .lift_errs()
        // force non-empty matrix
        .at_least(1)
        // force equal-sized rows
        .const_over(|vec| vec.len())
        // collect into a matrix
        .collect::<Result<Vec<_>, _>>();
    assert_eq!(mat, Ok(vec![vec![1.2, 3.0], vec![4.2, 0.5]]));
    print!("{:?}", mat)
}
```

Most of the documentation for this crate is just the docstrings for the various methods of the `ValidIter` trait, so that's (probably) the place to go if you're unsure about what some validation adapter does.

The things that validiter does not (yet) support and you might want, but won't
get, are:
- Error messages inside the ValidErr type.
- Tight compatability with the `anyhow` crate (https://docs.rs/anyhow/latest/anyhow/).

I'd love to hear suggestions about anything - ESPECIALLY if you think I'm doing something wrong in the definition or implementation of this crate.


## License


Licensed under either of

 * Apache License, Version 2.0
   ([LICENSE-APACHE]LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
 * MIT license
   ([LICENSE-MIT]LICENSE-MIT or http://opensource.org/licenses/MIT)

at your option.

## Contribution


Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.