use crate::measure::Measure;
use crate::node::Node;
pub trait Fold {
fn fold_node(&mut self, node: Node) -> Node {
fold_node(self, node)
}
fn fold_measure(&mut self, measure: Measure) -> Measure {
measure
}
}
pub fn fold_node<F: Fold + ?Sized>(f: &mut F, mut node: Node) -> Node {
node.children = node.children
.into_iter()
.map(|child| f.fold_node(child))
.collect();
node.payload = match node.payload {
crate::node::NodePayload::Leaf { measures, intensity } => {
crate::node::NodePayload::Leaf {
measures: measures.into_iter().map(|m| f.fold_measure(m)).collect(),
intensity,
}
}
crate::node::NodePayload::Exercise { measures, intensity, rest_seconds } => {
crate::node::NodePayload::Exercise {
measures: measures.into_iter().map(|m| f.fold_measure(m)).collect(),
intensity,
rest_seconds,
}
}
other => other,
};
node
}
#[cfg(test)]
mod tests {
use super::*;
use crate::measure::{Measure, WeightUnit};
use crate::node::*;
use std::collections::BTreeMap;
struct KgToLbs;
impl Fold for KgToLbs {
fn fold_measure(&mut self, measure: Measure) -> Measure {
match measure {
Measure::Weight { amount, unit: WeightUnit::Kg } => {
Measure::Weight { amount: amount * 2.20462, unit: WeightUnit::Lbs }
}
other => other,
}
}
}
#[test]
fn fold_converts_kg_to_lbs() {
let node = Node {
id: NodeId::from_string("s1"),
kind: NodeKind::Set,
name: None,
children: vec![],
payload: NodePayload::Leaf {
measures: vec![
Measure::Weight { amount: 100.0, unit: WeightUnit::Kg },
Measure::Reps(5),
],
intensity: None,
},
metadata: BTreeMap::new(),
};
let mut folder = KgToLbs;
let result = folder.fold_node(node);
if let NodePayload::Leaf { measures, .. } = &result.payload {
match &measures[0] {
Measure::Weight { amount, unit } => {
assert!((amount - 220.462).abs() < 0.01);
assert_eq!(*unit, WeightUnit::Lbs);
}
_ => panic!("expected Weight"),
}
assert_eq!(measures[1], Measure::Reps(5));
} else {
panic!("expected Leaf");
}
}
}