1use std::sync::{Arc, Mutex};
4
5use sim_kernel::{
6 Cx, Demand, EagerPolicy, Error, EvalPolicy, Expr, PreparedArgs, RawArgs, Result, ShapeMatch,
7 Value,
8};
9
10use crate::{LogicConfig, LogicDb, query::query_all};
11
12pub struct LogicPolicy {
17 db: Arc<Mutex<LogicDb>>,
18 config: LogicConfig,
19}
20
21impl LogicPolicy {
22 pub fn new(db: LogicDb, config: LogicConfig) -> Self {
24 Self {
25 db: Arc::new(Mutex::new(db)),
26 config,
27 }
28 }
29
30 pub fn from_shared(db: Arc<Mutex<LogicDb>>, config: LogicConfig) -> Self {
32 Self { db, config }
33 }
34
35 pub fn db(&self) -> Arc<Mutex<LogicDb>> {
37 Arc::clone(&self.db)
38 }
39}
40
41impl EvalPolicy for LogicPolicy {
42 fn name(&self) -> &'static str {
43 "logic"
44 }
45
46 fn prepare_call_args(
47 &self,
48 cx: &mut Cx,
49 raw: RawArgs,
50 demands: &[Demand],
51 ) -> Result<PreparedArgs> {
52 EagerPolicy.prepare_call_args(cx, raw, demands)
53 }
54
55 fn force(&self, cx: &mut Cx, value: Value, demand: Demand) -> Result<Value> {
56 EagerPolicy.force(cx, value, demand)
57 }
58
59 fn eval_expr(&self, cx: &mut Cx, expr: Expr) -> Result<Value> {
60 let answers = {
61 let db = self
62 .db
63 .lock()
64 .map_err(|_| Error::PoisonedLock("logic policy db"))?;
65 query_all(cx, &db, &self.config, expr, Some(1))?
66 };
67 match answers.into_iter().next() {
68 Some(answer) => answer_to_value(cx, answer),
69 None => cx.factory().nil(),
70 }
71 }
72}
73
74fn answer_to_value(cx: &mut Cx, answer: ShapeMatch) -> Result<Value> {
75 let mut entries = Vec::new();
76 for (name, value) in answer.captures.values() {
77 entries.push((name.clone(), value.clone()));
78 }
79 for (name, expr) in answer.captures.exprs() {
80 entries.push((name.clone(), cx.factory().expr(expr.clone())?));
81 }
82 cx.factory().table(entries)
83}