93 lines
2.2 KiB
Rust
93 lines
2.2 KiB
Rust
use crate::{Aggregatable, Aggregate, EString, ParseFragment};
|
|
|
|
/// Aggregate struct, that can multiply inner aggregatable [items](Aggregatable::items) if
|
|
/// [``Aggregatable::Item``] implements [``std::iter::Product``](std::iter::Product)
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```rust
|
|
/// use estring::{Aggregate, EString, SepVec, Product};
|
|
/// let res = EString::from("1*2*3*4")
|
|
/// .parse::<Product<SepVec<i32, '*'>>>()
|
|
/// .unwrap()
|
|
/// .agg();
|
|
/// assert_eq!(res, 24);
|
|
/// ```
|
|
#[derive(Debug, PartialEq, Eq)]
|
|
pub struct Product<T>(pub T);
|
|
|
|
impl<T> ParseFragment for Product<T>
|
|
where
|
|
T: ParseFragment,
|
|
{
|
|
fn parse_frag(es: EString) -> crate::Result<Self> {
|
|
T::parse_frag(es).map(Self)
|
|
}
|
|
}
|
|
|
|
impl<R, T> Aggregate for Product<T>
|
|
where
|
|
R: std::iter::Product,
|
|
T: Aggregatable<Item = R>,
|
|
{
|
|
type Target = R;
|
|
|
|
fn agg(self) -> Self::Target {
|
|
self.0.items().into_iter().product()
|
|
}
|
|
}
|
|
|
|
impl<R, T> Aggregatable for Product<T>
|
|
where
|
|
R: std::iter::Product,
|
|
T: Aggregatable<Item = R>,
|
|
{
|
|
type Item = R;
|
|
|
|
fn items(self) -> Vec<Self::Item> {
|
|
vec![self.agg()]
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::SepVec;
|
|
|
|
use super::*;
|
|
|
|
type CommaVec<T> = SepVec<T, ','>;
|
|
type MulVec<T> = SepVec<T, '*'>;
|
|
|
|
#[test]
|
|
fn should_parse_vec() {
|
|
let es = EString::from("1,2,3");
|
|
match es.parse::<Product<CommaVec<i32>>>() {
|
|
Ok(res) => assert_eq!(res, Product(CommaVec::from(vec![1, 2, 3]))),
|
|
_ => unreachable!(),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn should_aggregate_vector() {
|
|
let es = EString::from("1,2,3");
|
|
let expr = es.parse::<Product<CommaVec<i32>>>().unwrap();
|
|
assert_eq!(expr.agg(), 6);
|
|
}
|
|
|
|
#[test]
|
|
fn should_aggregate_vector_with_inner_vector() {
|
|
let es = EString::from("1*2,2,3");
|
|
let expr = es.parse::<Product<CommaVec<MulVec<i32>>>>().unwrap();
|
|
assert_eq!(expr.agg(), 12);
|
|
}
|
|
|
|
#[test]
|
|
fn should_aggregate_vector_with_inner_aggregation() {
|
|
let es = EString::from("1*2,2,3");
|
|
let expr = es
|
|
.parse::<Product<CommaVec<Product<MulVec<i32>>>>>()
|
|
.unwrap();
|
|
assert_eq!(expr.agg(), 12);
|
|
}
|
|
}
|