1use crate::ast::AstNode;
9use crate::decision::Verdict;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
16#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17#[repr(u8)]
18pub enum Paradigm {
19 Boolean = 0,
20 Modal = 1,
21 Epistemic = 2,
22 Deontic = 3,
23 Temporal = 4,
24 Fuzzy = 5,
25 Probabilistic = 6,
26 Paraconsistent = 7,
27 }
29
30impl Paradigm {
31 pub const ALL: &'static [Paradigm] = &[
32 Paradigm::Boolean,
33 Paradigm::Modal,
34 Paradigm::Epistemic,
35 Paradigm::Deontic,
36 Paradigm::Temporal,
37 Paradigm::Fuzzy,
38 Paradigm::Probabilistic,
39 Paradigm::Paraconsistent,
40 ];
41
42 pub fn name(self) -> &'static str {
43 match self {
44 Paradigm::Boolean => "boolean",
45 Paradigm::Modal => "modal",
46 Paradigm::Epistemic => "epistemic",
47 Paradigm::Deontic => "deontic",
48 Paradigm::Temporal => "temporal",
49 Paradigm::Fuzzy => "fuzzy",
50 Paradigm::Probabilistic => "probabilistic",
51 Paradigm::Paraconsistent => "paraconsistent",
52 }
53 }
54}
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq)]
59pub struct EngineId(pub u8);
60
61#[derive(Debug, Clone, PartialEq, Eq)]
63pub enum EngineError {
64 UnsupportedNode,
66 MissingContext(&'static str),
68 MalformedExpression,
70 ContradictionDetected,
72 DepthLimitExceeded,
74}
75
76impl EngineError {
77 pub fn as_str(&self) -> &'static str {
78 match self {
79 EngineError::UnsupportedNode => "unsupported_node",
80 EngineError::MissingContext(_) => "missing_context",
81 EngineError::MalformedExpression => "malformed_expression",
82 EngineError::ContradictionDetected => "contradiction_detected",
83 EngineError::DepthLimitExceeded => "depth_limit_exceeded",
84 }
85 }
86}
87
88#[cfg(feature = "std")]
89impl std::fmt::Display for EngineError {
90 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91 match self {
92 EngineError::UnsupportedNode => write!(f, "UnsupportedNode"),
93 EngineError::MissingContext(key) => write!(f, "MissingContext({key})"),
94 EngineError::MalformedExpression => write!(f, "MalformedExpression"),
95 EngineError::ContradictionDetected => write!(f, "ContradictionDetected"),
96 EngineError::DepthLimitExceeded => write!(f, "DepthLimitExceeded"),
97 }
98 }
99}
100
101#[cfg(feature = "std")]
102impl std::error::Error for EngineError {}
103
104pub struct EvalContext<'a> {
109 pub slots: &'a [(&'static str, ContextValue)],
111 pub logical_time: u64,
114 pub depth_limit: u8,
116}
117
118impl<'a> EvalContext<'a> {
119 pub fn get(&self, key: &'static str) -> Option<&ContextValue> {
120 self.slots.iter().find(|(k, _)| *k == key).map(|(_, v)| v)
121 }
122}
123
124#[derive(Debug, Clone, PartialEq)]
126pub enum ContextValue {
127 Bool(bool),
128 Integer(i64),
129 Float(f64),
130 Str(&'static str),
131 #[cfg(feature = "alloc")]
132 OwnedStr(alloc::string::String),
133}
134
135impl ContextValue {
136 pub fn as_bool(&self) -> Option<bool> {
137 if let ContextValue::Bool(b) = self {
138 Some(*b)
139 } else {
140 None
141 }
142 }
143 pub fn as_i64(&self) -> Option<i64> {
144 if let ContextValue::Integer(n) = self {
145 Some(*n)
146 } else {
147 None
148 }
149 }
150 pub fn as_f64(&self) -> Option<f64> {
151 if let ContextValue::Float(f) = self {
152 Some(*f)
153 } else {
154 None
155 }
156 }
157}
158
159pub trait LogicEngine {
164 fn id(&self) -> EngineId;
166
167 fn paradigm(&self) -> Paradigm;
169
170 fn name(&self) -> &'static str;
172
173 fn can_handle(&self, node: &AstNode) -> bool;
176
177 fn evaluate(&self, node: &AstNode, ctx: &EvalContext<'_>) -> Result<Verdict, EngineError>;
181}