1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
//! Constrain the set of types that you can reason about in a particular //! context. use crate::state::State; use crate::value::{LVar, Val}; use im_rc::HashMap; use std::fmt::Debug; /// Manage values for a set of specific types. /// /// Works with the [`DomainType<T>`](DomainType) trait to allow access to actual /// values. /// /// Domains are typically generated with the [`domain!`](./macro.domain.html) /// macro. There isn't currently much use case for interacting with a domain /// directly in user code. The only reason it is public is to allow implementing /// custom domains through the macro. /// /// ``` /// use canrun::{State, Goal, unify, var}; /// /// canrun::domain! { /// MyDomain { /// i32 /// } /// } /// /// # fn main() -> () { /// let x = var(); /// let state: State<MyDomain> = State::new(); /// let goal: Goal<MyDomain> = unify(x, 1); /// # } /// ``` pub trait Domain<'a>: Clone + Debug { /// An individual value that may contain any of the valid types in this /// domain. /// /// Typically for internal use. type Value: Debug + Clone + 'a; /// Create a new, valid domain. /// /// Typically for internal use. fn new() -> Self; /// Apply [`.unify()`](crate::state::State::unify()) to two [domain level /// values](crate::domains::Domain::Value). /// /// The unification will fail if the inner values are not of the same type. /// This should not be able to happen. /// /// Typically for internal use. fn unify_domain_values( state: State<'a, Self>, a: Self::Value, b: Self::Value, ) -> Option<State<'a, Self>>; } /// A type specific container used by a [`Domain`](crate::domains::Domain) to /// hold values. /// /// Created by the `domain!` macro and intended for internal use. #[derive(Debug)] pub struct DomainValues<T: Debug>(pub(crate) HashMap<LVar<T>, Val<T>>); impl<T: Debug> DomainValues<T> { #[doc(hidden)] pub fn new() -> Self { DomainValues(HashMap::new()) } } impl<'a, T: Debug> Clone for DomainValues<T> { fn clone(&self) -> Self { DomainValues(self.0.clone()) } } /// Allows a [`State`](crate::state) to retrieve values of a specific type from /// a [domain](crate::domains). /// /// This trait is automatically implemented by the `domain!` macro. /// /// As of now there shouldn't be much of a need to use this trait's /// functionality in user facing code. The trait itself may need to be used as a /// constraint, though [`UnifyIn`](crate::UnifyIn) is often the better, higher /// level choice. pub trait DomainType<'a, T: Debug>: Domain<'a> { #[doc(hidden)] fn resolve<'r>(&'r self, val: &'r Val<T>) -> &'r Val<T> where T: Debug, { match val { Val::Var(var) => { let resolved = self.values_as_ref().0.get(var); match resolved { Some(Val::Var(found)) if found == var => val, Some(found) => self.resolve(found), _ => val, } } value => value, } } #[doc(hidden)] fn update(&mut self, key: LVar<T>, value: Val<T>) { self.values_as_mut().0.insert(key, value); } #[doc(hidden)] fn values_as_ref(&self) -> &DomainValues<T>; #[doc(hidden)] fn values_as_mut(&mut self) -> &mut DomainValues<T>; #[doc(hidden)] fn into_domain_val(val: Val<T>) -> Self::Value; } /// Generate [Domain] structs and other associated types and impls. /// /// Manually implementing a [Domain] would be tedious and finicky. This macro /// attempts to simplify most of the general cases by building out everything /// required to reason about values of various types. /// /// A few [example domains](crate::example) are available for simple /// use cases. /// /// # Examples /// Begin each declaration with the domain keyword. /// ``` /// canrun::domain! { /// MyDomain { i32 } /// } /// # fn main() -> () {} /// # // keep this `-> ()` to quell `needless_doctest_main` warning /// # // https://github.com/rust-lang/rust-clippy/issues/4698 /// ``` /// /// The optional [visibility /// modifier](https://doc.rust-lang.org/reference/visibility-and-privacy.html) /// works just as in normal Rust. /// ``` /// canrun::domain! { /// pub MyPublicDomain { i32 } /// } /// # fn main() {} /// ``` /// /// You can define multiple values, include structures. Note that a wrapping /// [`Val`](crate::value::Val) is required in the tuple. /// ``` /// use canrun::Val; /// canrun::domain! { /// pub MyBigDomain { /// i32, /// String, /// (Val<i32>, Val<String>), /// } /// } /// # fn main() {} /// ``` /// /// Any types you add to a domain must implement the /// [`UnifyIn`](crate::unify::UnifyIn) trait. Canrun includes default /// implementations for almost all primitive types and collection types are /// available in [`canrun_collections`]. /// /// Once you have a domain, you can use it to parameterize other types, such as /// [`State`](crate::state::State) and [`Goal`](crate::goals::Goal): /// ``` /// # use canrun::state::State; /// # use canrun::goals::{Goal, unify}; /// # use canrun::value::var; /// # canrun::domain! { MyDomain { i32 } } /// # fn main() { /// # let x = var(); /// let state: State<MyDomain> = State::new(); /// let goal: Goal<MyDomain> = unify(x, 1); /// # } /// ``` pub use canrun_codegen::domain;