canrun 0.2.0

A logic programming library inspired by the *Kanren family of language DSLs.
Documentation
use crate::{Domain, DomainType, IntoVal, LVar, ResolvedState, Val};
use std::fmt::Debug;

/// Extract a fully resolved `T` from a [`Val<T>`](crate::value::Val).
///
/// Used by [query](crate::Query) to ensure that result values are fully and
/// recursively resolved.
pub trait ReifyIn<'a, D>: Sized {
    /// The "concrete" type that `Self` reifies to.
    type Reified;

    /// Extract a reified `Self` from a compatible
    /// [`ResolvedState`](crate::state::ResolvedState). This trait is usually
    /// used indirectly through the [`Query`](crate::Query) trait.
    ///
    /// # Examples:
    /// Simple values are typically copied or cloned (since the `Val` stores in
    /// an [Rc](std::rc::Rc) internally).
    /// ```
    /// use canrun::{Val, val, var, ReifyIn, IterResolved, State, ResolvedState};
    /// use canrun::example::{I32, TupleI32};
    /// State::new()
    ///     .iter_resolved()
    ///     .for_each(|state: ResolvedState<I32>| {
    ///         let x = val!(1);
    ///         assert_eq!(x.reify_in(&state), Some(1));
    ///     });
    /// ```
    /// Structures containing additional `Val`s should be recursively reified.
    /// ```
    /// # use canrun::{Val, val, var, ReifyIn, IterResolved, State, ResolvedState};
    /// # use canrun::example::{I32, TupleI32};
    /// State::new()
    ///     .iter_resolved()
    ///     .for_each(|state: ResolvedState<TupleI32>| {
    ///         let x = (val!(1), val!(2));
    ///         assert_eq!(x.reify_in(&state), Some((1, 2)));
    ///     });
    /// ```
    /// Returns `None` if the [`Val`] is unresolved.
    /// ```
    /// # use canrun::{Val, val, var, ReifyIn, IterResolved, State, ResolvedState};
    /// # use canrun::example::{I32, TupleI32};
    /// State::new()
    ///     .iter_resolved()
    ///     .for_each(|state: ResolvedState<I32>| {
    ///         let x: Val<i32> = val!(var());
    ///         assert_eq!(x.reify_in(&state), None);
    ///     });
    /// ```
    /// Also returns `None` if `Self` is a structure containing any unresolved
    /// `Val`s.
    /// ```
    /// # use canrun::{Val, val, var, ReifyIn, IterResolved, State, ResolvedState};
    /// # use canrun::example::{I32, TupleI32};
    /// State::new()
    ///     .iter_resolved()
    ///     .for_each(|state: ResolvedState<TupleI32>| {
    ///         let x: Val<i32> = val!(var());
    ///         let y = (x, val!(2));
    ///         assert_eq!(y.reify_in(&state), None);
    ///     });
    /// ```
    fn reify_in(&self, state: &ResolvedState<D>) -> Option<Self::Reified>;
}

impl<'a, T, D> ReifyIn<'a, D> for LVar<T>
where
    T: ReifyIn<'a, D> + Debug,
    D: DomainType<'a, T> + 'a,
{
    type Reified = T::Reified;
    fn reify_in(&self, state: &ResolvedState<D>) -> Option<Self::Reified> {
        self.into_val().reify_in(state)
    }
}

impl<'a, T, D> ReifyIn<'a, D> for Val<T>
where
    T: ReifyIn<'a, D> + Debug,
    D: DomainType<'a, T> + 'a,
{
    type Reified = T::Reified;
    fn reify_in(&self, state: &ResolvedState<D>) -> Option<Self::Reified> {
        let resolved = state.resolve_val(self).resolved().ok()?;
        resolved.reify_in(state)
    }
}

impl<'a, T, D> ReifyIn<'a, D> for &T
where
    T: ReifyIn<'a, D>,
    D: Domain<'a> + 'a,
{
    type Reified = T::Reified;
    fn reify_in(&self, state: &ResolvedState<D>) -> Option<Self::Reified> {
        (*self).reify_in(state)
    }
}

#[cfg(test)]
mod tests {
    use crate::example::I32;
    use crate::{val, var, IterResolved, ReifyIn, ResolvedState, State, Val};

    #[test]
    fn reify_var() {
        let x: Val<i32> = val!(var());
        State::new()
            .iter_resolved()
            .for_each(|state: ResolvedState<I32>| {
                assert_eq!(x.reify_in(&state), None);
            });
    }

    #[test]
    fn reify_resolved() {
        let x = val!(1);
        State::new()
            .iter_resolved()
            .for_each(|state: ResolvedState<I32>| {
                assert_eq!(x.reify_in(&state), Some(1));
            });
    }
}