1use serde::Serialize; 2 3use crate::{Domain, Known, Network, Next, Then}; 4 5/// The sources of a host's facts, as callbacks: [`Network::run`] calls them, 6/// and they are the only place a fact is supplied from. 7pub trait Host<D: Domain> { 8 /// One request for every fact the network wants from outside it. Returns 9 /// what it taught; a fact left out was not supplied. 10 fn ask(&mut self, facts: &[D::Fact]) -> Vec<(D::Fact, D::Value)>; 11 /// Does an effect, and returns what it taught. It must teach 12 /// [`Domain::teaches`] its effect, or the run stops. 13 fn perform(&mut self, effect: D::Effect) -> Vec<(D::Fact, D::Value)>; 14} 15 16/// How a run ended. 17#[derive(Clone, Debug, PartialEq, Eq)] 18pub enum Outcome<D: Domain> { 19 /// No rule has anything left to do: what to show is in the notes of the 20 /// rules that hold. 21 Done, 22 /// A rule ended the query outright. 23 Ended(D::End), 24 /// The host did not supply these facts, so the run could not go on. 25 Stuck(Vec<D::Fact>), 26} 27 28/// A rule that decided a step, and what it stood on. 29#[derive(Clone, Debug, PartialEq, Eq)] 30pub struct Firing<D: Domain> { 31 /// Index into [`Network::terminals`]. 32 pub rule: usize, 33 pub name: String, 34 pub then: Then<D>, 35 /// The facts the rule's tests are on, with what each was: not what any of 36 /// them was about. 37 pub on: Vec<(D::Fact, D::Value)>, 38} 39 40/// One thing that happened in a run. 41#[derive(Clone, Debug, PartialEq, Eq)] 42pub enum Event<D: Domain> { 43 /// These facts were asked for in one request. 44 Asked(Vec<D::Fact>), 45 /// A rule decided the next step. 46 Fired(Firing<D>), 47 /// A source taught these. 48 Learned(Vec<(D::Fact, D::Value)>), 49 Stopped(Outcome<D>), 50} 51 52/// 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} 57 58impl<D: Domain> Default for Trace<D> { 59 fn default() -> Self { 60 Trace { events: Vec::new() } 61 } 62} 63 64/// An event as data to log: names, ids and counts, never what a fact was 65/// 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, 69 /// `asked`, `fired`, `learned`, `done`, `ended` or `stuck`. 70 pub event: &'static str, 71 /// 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>, 76 /// For `fired`: the kind (`do`, `end`, `note`) and name of what it does, 77 /// and for `ended` the end's name. 78 #[serde(skip_serializing_if = "Option::is_none")] 79 pub then: Option<String>, 80 /// The facts the event is about: asked for, stood on, learned or missing. 81 pub facts: Vec<String>, 82 /// For `fired` and `learned`: the value of each fact, in the same order. 83 pub values: Vec<String>, 84 pub count: usize, 85} 86 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> { 135 /// 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 } 139 140 /// The rules that decided a step, in order, as indices into the network's 141 /// 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} 152 153/// 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} 160 161impl<D: Domain> Network<D> { 162 /// Does what [`Network::decide`] says until the query ends, asking `host` 163 /// for facts and for effects, and recording a trace. 164 /// 165 /// Stops with [`Outcome::Stuck`] rather than looping when the host leaves 166 /// 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}