Function contrafact::facts::prism
source · pub fn prism<'a, O, T, P>(
label: impl ToString,
prism: P,
inner_fact: impl Fact<'a, T>
) -> impl Fact<'a, O>where
O: Target<'a>,
T: Target<'a>,
P: 'a + Send + Sync + Fn(&mut O) -> Option<&mut T>,
Expand description
Lifts a Fact about some optional subset of data into a Fact about the superset.
In other words, if type O
contains a Option<T>
, and you have a Fact<T>
,
PrismFact
lets you lift that fact into a Fact<O>
.
The prism
closure provides an optional mutable view into the subset.
If the prism returns None during any fact application, the fact will
effectively be skipped for this item: no check or mutation will be performed,
and the state will not advance.
A prism is like a lens, except that the target value may or may not exist. It is typically used for enums, or any structure where data may or may not be present.
use contrafact::*;
use arbitrary::{Arbitrary, Unstructured};
#[derive(Debug, Clone, PartialEq, Arbitrary)]
enum E {
X(u32),
Y(u32),
}
impl E {
fn x(&mut self) -> Option<&mut u32> {
match self {
E::X(x) => Some(x),
_ => None,
}
}
fn y(&mut self) -> Option<&mut u32> {
match self {
E::Y(y) => Some(y),
_ => None,
}
}
}
let mut fact = prism("E::x", E::x, eq(1));
assert!(fact.clone().check(&E::X(1)).is_ok());
assert!(fact.clone().check(&E::X(2)).is_err());
assert!(fact.clone().check(&E::Y(99)).is_ok());
let mut g = utils::random_generator();
let e = fact.build(&mut g);
match e {
E::X(x) => assert_eq!(x, 1),
_ => (), // Y is not defined by the prism, so it can take on any value.
};
The prism
closure is a rather lazy way to provide a prism in the
traditional optics sense. We may consider using a true lens library for
this in the future.