1use std::collections::BTreeMap;
2use std::fmt::Debug;
3
4/// What a host supplies: the facts its rules are about, the values they can
5/// take, and what a rule may do. A domain is a marker type, so it is `Copy`
6/// and the engine's types can derive from it.
7///
8/// Names are the vocabulary of rules written as data. They are also what a
9/// [`crate::Record`] carries, so a name is never content: a fact's name, never
10/// what it was about.
11pub trait Domain: Copy + Debug + Eq + 'static {
12    /// Something that can be known. Ordered, so that the facts a request
13    /// asks for come in a stable order.
14    type Fact: Copy + Ord + Debug + 'static;
15    /// What a fact can turn out to be.
16    type Value: Copy + Eq + Debug + 'static;
17    /// Something a rule does that teaches a fact ([`Domain::teaches`]).
18    type Effect: Copy + Eq + Debug + 'static;
19    /// How a rule ends the query outright.
20    type End: Copy + Eq + Debug + 'static;
21    /// Something that is so when a rule holds, and that decides no step.
22    type Note: Copy + Eq + Debug + 'static;
23
24    /// Every fact, in the order a drawing lists them.
25    fn facts() -> &'static [Self::Fact];
26    /// The fact's name: unique among the facts.
27    fn fact_name(fact: Self::Fact) -> &'static str;
28    /// Everything the fact can turn out to be, so a test on any other value
29    /// is refused when a rule is loaded.
30    fn values(fact: Self::Fact) -> &'static [Self::Value];
31    /// The value's name: unique among one fact's values.
32    fn value_name(value: Self::Value) -> &'static str;
33    /// Whether a source outside the network supplies the fact when asked, in
34    /// the one request that asks for every such fact together. A fact that
35    /// is not is taught by an effect.
36    fn asked_for(fact: Self::Fact) -> bool;
37    /// The fact an effect teaches. An effect whose fact is already known has
38    /// been done.
39    fn teaches(effect: Self::Effect) -> Self::Fact;
40
41    fn effect_name(effect: Self::Effect) -> String;
42    fn end_name(end: Self::End) -> String;
43    fn note_name(note: Self::Note) -> String;
44
45    /// The effect a rule loaded as data names, or why this domain does not
46    /// allow it. Refusing is the default: a domain opts each kind in.
47    fn parse_effect(name: &str) -> Result<Self::Effect, String> {
48        Err(format!("this domain allows no effect, and `{name}` is one"))
49    }
50    /// As [`Domain::parse_effect`], for an end.
51    fn parse_end(name: &str) -> Result<Self::End, String> {
52        Err(format!("this domain allows no end, and `{name}` is one"))
53    }
54    /// As [`Domain::parse_effect`], for a note.
55    fn parse_note(name: &str) -> Result<Self::Note, String> {
56        Err(format!("this domain allows no note, and `{name}` is one"))
57    }
58}
59
60/// One test on one fact: an alpha node.
61#[derive(Clone, Copy, Debug, PartialEq, Eq)]
62pub enum Test<D: Domain> {
63    Is(D::Fact, D::Value),
64    /// The fact is known, whatever it is.
65    Known(D::Fact),
66}
67
68impl<D: Domain> Test<D> {
69    pub fn fact(self) -> D::Fact {
70        match self {
71            Test::Is(fact, _) | Test::Known(fact) => fact,
72        }
73    }
74
75    /// The test without its fact's name, as a drawing labels the node.
76    pub fn label(self) -> String {
77        match self {
78            Test::Is(_, value) => format!("= {}", D::value_name(value)),
79            Test::Known(_) => "is known".to_owned(),
80        }
81    }
82}
83
84/// What a rule does when it holds.
85#[derive(Clone, Copy, Debug, PartialEq, Eq)]
86pub enum Then<D: Domain> {
87    /// Go and make a call that teaches a fact.
88    Do(D::Effect),
89    /// Stop with this.
90    End(D::End),
91    /// Something is so, and no step is decided.
92    Note(D::Note),
93}
94
95/// A rule written in code. Order is priority: of the rules that hold, the
96/// first with something left to do decides.
97#[derive(Clone, Copy, Debug)]
98pub struct Rule<'a, D: Domain> {
99    pub name: &'a str,
100    pub when: &'a [Test<D>],
101    pub then: Then<D>,
102}
103
104/// What is known so far.
105#[derive(Clone, Debug, PartialEq)]
106pub struct Known<D: Domain>(BTreeMap<D::Fact, D::Value>);
107
108impl<D: Domain> Default for Known<D> {
109    fn default() -> Self {
110        Known(BTreeMap::new())
111    }
112}
113
114impl<D: Domain> Known<D> {
115    pub fn learn(&mut self, fact: D::Fact, value: D::Value) {
116        self.0.insert(fact, value);
117    }
118
119    pub fn get(&self, fact: D::Fact) -> Option<D::Value> {
120        self.0.get(&fact).copied()
121    }
122
123    pub fn forget(&mut self, fact: D::Fact) {
124        self.0.remove(&fact);
125    }
126
127    /// How many facts are known.
128    pub fn len(&self) -> usize {
129        self.0.len()
130    }
131
132    pub fn is_empty(&self) -> bool {
133        self.0.is_empty()
134    }
135}