use ordofp::optics::{Aspectus, Divisio};
pub fn lens_get_put<S, A, GetFn, SetFn>(lens: &Aspectus<S, A, GetFn, SetFn>, s: &S) -> bool
where
S: PartialEq,
GetFn: Fn(&S) -> A,
SetFn: Fn(&S, A) -> S,
{
lens.set(s, lens.get(s)) == *s
}
pub fn lens_put_get<S, A, GetFn, SetFn>(lens: &Aspectus<S, A, GetFn, SetFn>, s: &S, a: A) -> bool
where
A: Clone + PartialEq,
GetFn: Fn(&S) -> A,
SetFn: Fn(&S, A) -> S,
{
lens.get(&lens.set(s, a.clone())) == a
}
pub fn lens_put_put<S, A, GetFn, SetFn>(
lens: &Aspectus<S, A, GetFn, SetFn>,
s: &S,
a1: A,
a2: A,
) -> bool
where
S: PartialEq,
A: Clone,
GetFn: Fn(&S) -> A,
SetFn: Fn(&S, A) -> S,
{
lens.set(&lens.set(s, a1), a2.clone()) == lens.set(s, a2)
}
pub fn prism_preview_review<S, A, PreviewFn, ReviewFn>(
prism: &Divisio<S, A, PreviewFn, ReviewFn>,
a: A,
) -> bool
where
A: Clone + PartialEq,
PreviewFn: Fn(&S) -> Option<A>,
ReviewFn: Fn(A) -> S,
{
prism.preview(&prism.review(a.clone())) == Some(a)
}
pub fn prism_review_preview<S, A, PreviewFn, ReviewFn>(
prism: &Divisio<S, A, PreviewFn, ReviewFn>,
s: &S,
) -> bool
where
S: PartialEq,
PreviewFn: Fn(&S) -> Option<A>,
ReviewFn: Fn(A) -> S,
{
match prism.preview(s) {
Some(a) => prism.review(a) == *s,
None => true,
}
}
#[cfg(test)]
mod tests {
use super::*;
use ordofp::optics::{aspectus, divisio};
use quickcheck::quickcheck;
#[derive(Clone, Debug, PartialEq)]
struct Point {
x: i32,
y: i32,
}
fn x_lens() -> Aspectus<Point, i32, impl Fn(&Point) -> i32, impl Fn(&Point, i32) -> Point> {
aspectus(|p: &Point| p.x, |p: &Point, x: i32| Point { x, y: p.y })
}
#[derive(Clone, Debug, PartialEq)]
enum Shape {
Circle(i64),
Rectangle(i64, i64),
}
fn circle_prism() -> Divisio<Shape, i64, impl Fn(&Shape) -> Option<i64>, impl Fn(i64) -> Shape>
{
divisio(
|s: &Shape| match s {
Shape::Circle(r) => Some(*r),
Shape::Rectangle(..) => None,
},
Shape::Circle,
)
}
quickcheck! {
fn point_x_lens_get_put(x: i32, y: i32) -> bool {
lens_get_put(&x_lens(), &Point { x, y })
}
fn point_x_lens_put_get(x: i32, y: i32, a: i32) -> bool {
lens_put_get(&x_lens(), &Point { x, y }, a)
}
fn point_x_lens_put_put(x: i32, y: i32, a1: i32, a2: i32) -> bool {
lens_put_put(&x_lens(), &Point { x, y }, a1, a2)
}
fn circle_prism_preview_review(r: i64) -> bool {
prism_preview_review(&circle_prism(), r)
}
fn circle_prism_review_preview(circle: bool, a: i64, b: i64) -> bool {
let shape = if circle { Shape::Circle(a) } else { Shape::Rectangle(a, b) };
prism_review_preview(&circle_prism(), &shape)
}
}
#[test]
fn unlawful_lens_fails_put_get() {
let broken = aspectus(|p: &Point| p.x, |p: &Point, _x: i32| p.clone());
assert!(!lens_put_get(&broken, &Point { x: 1, y: 2 }, 42));
}
}