canrun 0.2.0

A logic programming library inspired by the *Kanren family of language DSLs.
Documentation
use crate::domains::DomainType;
use crate::example::I32;
use crate::goals::custom;
use crate::goals::unify;
use crate::goals::Goal;
use crate::state::constraints::{Constraint, ResolveFn, VarWatch};
use crate::state::State;
use crate::util;
use crate::value::{
    val, var, IntoVal, Val,
    Val::{Resolved, Var},
};
use std::fmt;
use std::fmt::Debug;
use std::rc::Rc;

struct Assert<'a, T: Debug> {
    val: Val<T>,
    assert: Rc<dyn Fn(&T) -> bool + 'a>,
}

impl<'a, T: fmt::Debug> fmt::Debug for Assert<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Assert({:?})", self.val)
    }
}

impl<'a, T, D> Constraint<'a, D> for Assert<'a, T>
where
    T: Debug + 'a,
    D: DomainType<'a, T>,
{
    fn attempt(&self, state: &State<'a, D>) -> Result<ResolveFn<'a, D>, VarWatch> {
        let resolved = state.resolve_val(&self.val).clone();
        match resolved {
            Resolved(val) => {
                let assert = self.assert.clone();
                Ok(Box::new(
                    move |state: State<'a, D>| if assert(&*val) { Some(state) } else { None },
                ))
            }
            Var(var) => Err(VarWatch::one(var)),
        }
    }
}

pub(crate) fn assert<'a, T, V, D, F>(val: V, func: F) -> Rc<dyn Constraint<'a, D> + 'a>
where
    T: Debug + 'a,
    V: IntoVal<T> + Clone + 'a,
    D: DomainType<'a, T> + 'a,
    F: Fn(&T) -> bool + 'a,
{
    Rc::new(Assert {
        val: val.into_val(),
        assert: Rc::new(func),
    })
}

#[test]
fn basic_constrain_succeeds() {
    let x = var();
    let goals: Vec<Goal<I32>> = vec![
        unify(2, x),
        custom(|s| s.constrain(assert(x, |x| x > &1))),
        custom(|s| s.constrain(assert(x, |x| x > &0))),
    ];
    util::assert_permutations_resolve_to(goals, x, vec![2]);
}

#[test]
fn basic_constrain_fails() {
    let x = var();
    let goals: Vec<Goal<I32>> = vec![
        unify(&val!(2), x.clone()),
        custom(|s| s.constrain(assert(x.clone(), |x| x > &1))),
        custom(|s| s.constrain(assert(x, |x| x > &3))),
    ];
    util::assert_permutations_resolve_to(goals, x, vec![]);
}

#[test]
fn unsatisfied_constrain_fails() {
    let x = var();
    let y = var();
    let goals: Vec<Goal<I32>> = vec![
        unify(&val!(1), x),
        custom(|s| s.constrain(assert(y, |y| y < &3))),
    ];
    util::assert_permutations_resolve_to(goals.clone(), x, vec![]);
    util::assert_permutations_resolve_to(goals, y, vec![]);
}