1use fnv::FnvHashMap;
2use serde::{Deserialize, Serialize};
3
4pub type AtomId = u32;
5pub type VarId = u32;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct StringInterner {
11 to_id: FnvHashMap<String, AtomId>,
12 to_str: Vec<String>,
13}
14
15impl StringInterner {
16 pub fn new() -> Self {
17 StringInterner {
18 to_id: FnvHashMap::default(),
19 to_str: Vec::new(),
20 }
21 }
22
23 pub fn intern(&mut self, s: &str) -> AtomId {
25 if let Some(&id) = self.to_id.get(s) {
26 return id;
27 }
28 let id = self.to_str.len() as AtomId;
29 self.to_str.push(s.to_string());
30 self.to_id.insert(s.to_string(), id);
31 id
32 }
33
34 pub fn resolve(&self, id: AtomId) -> &str {
36 &self.to_str[id as usize]
37 }
38
39 pub fn try_resolve(&self, id: AtomId) -> Option<&str> {
41 self.to_str.get(id as usize).map(|s| s.as_str())
42 }
43
44 pub fn lookup(&self, s: &str) -> Option<AtomId> {
46 self.to_id.get(s).copied()
47 }
48
49 pub fn len(&self) -> usize {
50 self.to_str.len()
51 }
52
53 pub fn is_empty(&self) -> bool {
54 self.to_str.is_empty()
55 }
56}
57
58impl Default for StringInterner {
59 fn default() -> Self {
60 Self::new()
61 }
62}
63
64#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
66pub enum FirstArgKey {
67 Atom(AtomId),
68 Integer(i64),
69 Functor(AtomId, usize), }
71
72#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
74pub enum Term {
75 Atom(AtomId),
76 Var(VarId),
77 Integer(i64),
78 Float(f64),
79 Compound { functor: AtomId, args: Vec<Term> },
80 List { head: Box<Term>, tail: Box<Term> },
81}
82
83impl Term {
84 pub fn functor_arity(&self) -> Option<(AtomId, usize)> {
89 match self {
90 Term::Atom(id) => Some((*id, 0)),
91 Term::Compound { functor, args } => Some((*functor, args.len())),
92 _ => None,
93 }
94 }
95
96 pub fn first_arg_key(&self) -> Option<FirstArgKey> {
98 let first = match self {
99 Term::Compound { args, .. } if !args.is_empty() => &args[0],
100 _ => return None,
101 };
102 match first {
103 Term::Atom(id) => Some(FirstArgKey::Atom(*id)),
104 Term::Integer(n) => Some(FirstArgKey::Integer(*n)),
105 Term::Compound { functor, args } => Some(FirstArgKey::Functor(*functor, args.len())),
106 _ => None, }
108 }
109
110 pub fn is_var(&self) -> bool {
112 matches!(self, Term::Var(_))
113 }
114}
115
116#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
119pub struct Clause {
120 pub head: Term,
121 pub body: Vec<Term>,
122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127
128 #[test]
129 fn test_string_interner_basic() {
130 let mut interner = StringInterner::new();
131 let a = interner.intern("hello");
132 let b = interner.intern("world");
133 let c = interner.intern("hello"); assert_eq!(a, c);
136 assert_ne!(a, b);
137 assert_eq!(interner.resolve(a), "hello");
138 assert_eq!(interner.resolve(b), "world");
139 assert_eq!(interner.len(), 2);
140 }
141
142 #[test]
143 fn test_string_interner_lookup() {
144 let mut interner = StringInterner::new();
145 interner.intern("foo");
146
147 assert_eq!(interner.lookup("foo"), Some(0));
148 assert_eq!(interner.lookup("bar"), None);
149 }
150
151 #[test]
152 fn test_term_functor_arity() {
153 let atom = Term::Atom(0);
154 assert_eq!(atom.functor_arity(), Some((0, 0)));
155
156 let compound = Term::Compound {
157 functor: 1,
158 args: vec![Term::Atom(2), Term::Var(0)],
159 };
160 assert_eq!(compound.functor_arity(), Some((1, 2)));
161
162 let var = Term::Var(0);
163 assert_eq!(var.functor_arity(), None);
164
165 let int = Term::Integer(42);
166 assert_eq!(int.functor_arity(), None);
167 }
168
169 #[test]
170 fn test_first_arg_key() {
171 let t = Term::Compound {
173 functor: 0,
174 args: vec![Term::Atom(1)],
175 };
176 assert_eq!(t.first_arg_key(), Some(FirstArgKey::Atom(1)));
177
178 let t = Term::Compound {
180 functor: 0,
181 args: vec![Term::Integer(42)],
182 };
183 assert_eq!(t.first_arg_key(), Some(FirstArgKey::Integer(42)));
184
185 let t = Term::Compound {
187 functor: 0,
188 args: vec![Term::Var(0)],
189 };
190 assert_eq!(t.first_arg_key(), None);
191
192 let t = Term::Atom(0);
194 assert_eq!(t.first_arg_key(), None);
195 }
196
197 #[test]
198 fn test_clause_construction() {
199 let clause = Clause {
200 head: Term::Compound {
201 functor: 0,
202 args: vec![Term::Atom(1), Term::Var(0)],
203 },
204 body: vec![Term::Compound {
205 functor: 2,
206 args: vec![Term::Var(0)],
207 }],
208 };
209 assert_eq!(clause.body.len(), 1);
210 assert_eq!(clause.head.functor_arity(), Some((0, 2)));
211 }
212
213 #[test]
214 fn test_term_serialization() {
215 let term = Term::Compound {
216 functor: 0,
217 args: vec![Term::Atom(1), Term::Integer(42)],
218 };
219 let bytes = bincode::serialize(&term).unwrap();
220 let restored: Term = bincode::deserialize(&bytes).unwrap();
221 assert_eq!(term, restored);
222 }
223}