rustcrates.git / rete / src / trace.rs
trace.rsannotatedtrace.rssource196 lines · 7.2 KB · raw
1use serde::Serialize;
2
3use crate::{Domain, Known, Network, Next, Then};

The sources of a host's facts, as callbacks: [Network::run] calls them, and they are the only place a fact is supplied from.

7pub trait Host<D: Domain> {

One request for every fact the network wants from outside it. Returns what it taught; a fact left out was not supplied.

10    fn ask(&mut self, facts: &[D::Fact]) -> Vec<(D::Fact, D::Value)>;

Does an effect, and returns what it taught. It must teach [Domain::teaches] its effect, or the run stops.

13    fn perform(&mut self, effect: D::Effect) -> Vec<(D::Fact, D::Value)>;
14}

How a run ended.

17#[derive(Clone, Debug, PartialEq, Eq)]
18pub enum Outcome<D: Domain> {

No rule has anything left to do: what to show is in the notes of the rules that hold.

21    Done,

A rule ended the query outright.

23    Ended(D::End),

The host did not supply these facts, so the run could not go on.

25    Stuck(Vec<D::Fact>),
26}

A rule that decided a step, and what it stood on.

29#[derive(Clone, Debug, PartialEq, Eq)]
30pub struct Firing<D: Domain> {

Index into [Network::terminals].

32    pub rule: usize,
33    pub name: String,
34    pub then: Then<D>,

The facts the rule's tests are on, with what each was: not what any of them was about.

37    pub on: Vec<(D::Fact, D::Value)>,
38}

One thing that happened in a run.

41#[derive(Clone, Debug, PartialEq, Eq)]
42pub enum Event<D: Domain> {

These facts were asked for in one request.

44    Asked(Vec<D::Fact>),

A rule decided the next step.

46    Fired(Firing<D>),

A source taught these.

48    Learned(Vec<(D::Fact, D::Value)>),
49    Stopped(Outcome<D>),
50}

Every event of a run, in order.

53#[derive(Clone, Debug, PartialEq, Eq)]
54pub struct Trace<D: Domain> {
55    pub events: Vec<Event<D>>,
56}
58impl<D: Domain> Default for Trace<D> {
59    fn default() -> Self {
60        Trace { events: Vec::new() }
61    }
62}

An event as data to log: names, ids and counts, never what a fact was about. step is the event's place in its trace, from 0.

66#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
67pub struct Record {
68    pub step: usize,

asked, fired, learned, done, ended or stuck.

70    pub event: &'static str,

For fired: the rule's index and name.

72    #[serde(skip_serializing_if = "Option::is_none")]
73    pub rule: Option<usize>,
74    #[serde(skip_serializing_if = "Option::is_none")]
75    pub name: Option<String>,

For fired: the kind (do, end, note) and name of what it does, and for ended the end's name.

78    #[serde(skip_serializing_if = "Option::is_none")]
79    pub then: Option<String>,

The facts the event is about: asked for, stood on, learned or missing.

81    pub facts: Vec<String>,

For fired and learned: the value of each fact, in the same order.

83    pub values: Vec<String>,
84    pub count: usize,
85}
87fn named<D: Domain>(pairs: &[(D::Fact, D::Value)]) -> (Vec<String>, Vec<String>) {
88    (
89        pairs.iter().map(|(fact, _)| D::fact_name(*fact).to_owned()).collect(),
90        pairs.iter().map(|(_, value)| D::value_name(*value).to_owned()).collect(),
91    )
92}
93
94fn fact_names<D: Domain>(facts: &[D::Fact]) -> Vec<String> {
95    facts.iter().map(|fact| D::fact_name(*fact).to_owned()).collect()
96}
97
98impl<D: Domain> Event<D> {
99    pub fn record(&self, step: usize) -> Record {
100        let blank = Record { step, event: "", rule: None, name: None, then: None, facts: Vec::new(), values: Vec::new(), count: 0 };
101        match self {
102            Event::Asked(facts) => Record { event: "asked", facts: fact_names::<D>(facts), count: facts.len(), ..blank },
103            Event::Fired(firing) => {
104                let (facts, values) = named::<D>(&firing.on);
105                let then = match firing.then {
106                    Then::Do(effect) => format!("do {}", D::effect_name(effect)),
107                    Then::End(end) => format!("end {}", D::end_name(end)),
108                    Then::Note(note) => format!("note {}", D::note_name(note)),
109                };
110                Record {
111                    event: "fired",
112                    rule: Some(firing.rule),
113                    name: Some(firing.name.clone()),
114                    then: Some(then),
115                    count: facts.len(),
116                    facts,
117                    values,
118                    ..blank
119                }
120            }
121            Event::Learned(pairs) => {
122                let (facts, values) = named::<D>(pairs);
123                Record { event: "learned", count: facts.len(), facts, values, ..blank }
124            }
125            Event::Stopped(Outcome::Done) => Record { event: "done", ..blank },
126            Event::Stopped(Outcome::Ended(end)) => Record { event: "ended", then: Some(D::end_name(*end)), ..blank },
127            Event::Stopped(Outcome::Stuck(facts)) => {
128                Record { event: "stuck", facts: fact_names::<D>(facts), count: facts.len(), ..blank }
129            }
130        }
131    }
132}
133
134impl<D: Domain> Trace<D> {

The trace as records, ready to log as JSON lines.

136    pub fn records(&self) -> Vec<Record> {
137        self.events.iter().enumerate().map(|(step, event)| event.record(step)).collect()
138    }

The rules that decided a step, in order, as indices into the network's terminals: what a drawing numbers.

142    pub fn fired(&self) -> Vec<usize> {
143        self.events
144            .iter()
145            .filter_map(|event| match event {
146                Event::Fired(firing) => Some(firing.rule),
147                _ => None,
148            })
149            .collect()
150    }
151}

What a run came to.

154#[derive(Clone, Debug)]
155pub struct Run<D: Domain> {
156    pub outcome: Outcome<D>,
157    pub known: Known<D>,
158    pub trace: Trace<D>,
159}
161impl<D: Domain> Network<D> {

Does what [Network::decide] says until the query ends, asking host for facts and for effects, and recording a trace.

Stops with [Outcome::Stuck] rather than looping when the host leaves a wanted fact unsupplied.

167    pub fn run(&self, mut known: Known<D>, host: &mut impl Host<D>) -> Run<D> {
168        let mut trace = Trace::default();
169        let outcome = loop {
170            let (by, next) = self.decide(&known);
171            if let Some(rule) = by {
172                trace.events.push(Event::Fired(self.explain(rule, &known)));
173            }
174            let (wanted, taught) = match next {
175                Next::Done => break Outcome::Done,
176                Next::End(end) => break Outcome::Ended(end),
177                Next::Ask(facts) => {
178                    trace.events.push(Event::Asked(facts.clone()));
179                    let taught = host.ask(&facts);
180                    (facts, taught)
181                }
182                Next::Do(effect) => (vec![D::teaches(effect)], host.perform(effect)),
183            };
184            for (fact, value) in &taught {
185                known.learn(*fact, *value);
186            }
187            trace.events.push(Event::Learned(taught));
188            let missing: Vec<D::Fact> = wanted.into_iter().filter(|fact| known.get(*fact).is_none()).collect();
189            if !missing.is_empty() {
190                break Outcome::Stuck(missing);
191            }
192        };
193        trace.events.push(Event::Stopped(outcome.clone()));
194        Run { outcome, known, trace }
195    }
196}