1use crate::{Arena, Handle, Term, TermError};
6use core::fmt;
7use std::cmp::Ordering;
8
9impl fmt::Debug for View<'_> {
10 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
11 match &self {
12 View::Int(i) => f.debug_tuple("Int").field(&i).finish(),
13 View::Real(r) => f.debug_tuple("Real").field(&r).finish(),
14 View::Date(d) => f.debug_tuple("Date").field(&d).finish(),
15 View::Var(v) => f.debug_tuple("Var").field(&v).finish(),
16 View::Atom(a) => f.debug_tuple("Atom").field(&a).finish(),
17 View::Str(s) => f.debug_tuple("Str").field(&s).finish(),
18 View::Bin(b) => f.debug_tuple("Bin").field(&b).finish(),
19 View::Func(a, fr, ts) => f
20 .debug_tuple("Func")
21 .field(&a.arena_id)
22 .field(&fr)
23 .field(&ts.iter().map(|t| t.view(a)).collect::<Vec<_>>())
24 .finish(),
25 View::List(a, ts, tail) => f
26 .debug_tuple("List")
27 .field(&a.arena_id)
28 .field(&ts.iter().map(|t| t.view(a)).collect::<Vec<_>>())
29 .field(&tail.view(a))
30 .finish(),
31 View::Tuple(a, ts) => f
32 .debug_tuple("Tuple")
33 .field(&a.arena_id)
34 .field(&ts.iter().map(|t| t.view(a)).collect::<Vec<_>>())
35 .finish(),
36 }
37 }
38}
39
40#[derive(Clone, Copy)]
50pub enum View<'a> {
51 Int(i64),
53 Real(f64),
55 Date(i64),
57 Var(&'a str),
59 Atom(&'a str),
61 Str(&'a str),
63 Bin(&'a [u8]),
65 Func(&'a Arena, &'a Term, &'a [Term]),
70 List(&'a Arena, &'a [Term], &'a Term),
75 Tuple(&'a Arena, &'a [Term]),
79}
80
81impl Term {
82 #[inline]
87 pub fn view<'a>(&'a self, arena: &'a Arena) -> Result<View<'a>, TermError> {
88 match &self.0 {
89 Handle::Int(i) => Ok(View::Int(*i)),
90 Handle::Real(f) => Ok(View::Real(*f)),
91 Handle::Date(d) => Ok(View::Date(*d)),
92 Handle::Var(vs) => {
93 let s_bytes = &vs.bytes[..vs.len as usize];
94 let s = unsafe { core::str::from_utf8_unchecked(s_bytes) };
95 Ok(View::Var(s))
96 }
97 Handle::VarRef(vr) => Ok(View::Var(unsafe {
98 core::str::from_utf8_unchecked(
99 arena
100 .byte_slice(vr)
101 .map_err(|_| TermError::InvalidTerm(*self))?,
102 )
103 })),
104 Handle::Atom(a) => {
105 let s_bytes = &a.bytes[..a.len as usize];
106 let s = unsafe { core::str::from_utf8_unchecked(s_bytes) };
107 Ok(View::Atom(s))
108 }
109 Handle::AtomRef(ar) => Ok(View::Atom(unsafe {
110 core::str::from_utf8_unchecked(
111 arena
112 .byte_slice(ar)
113 .map_err(|_| TermError::InvalidTerm(*self))?,
114 )
115 })),
116 Handle::Str(ss) => {
117 let s_bytes = &ss.bytes[..ss.len as usize];
118 let s = unsafe { core::str::from_utf8_unchecked(s_bytes) };
119 Ok(View::Str(s))
120 }
121 Handle::StrRef(sr) => Ok(View::Str(unsafe {
122 core::str::from_utf8_unchecked(
123 arena
124 .byte_slice(sr)
125 .map_err(|_| TermError::InvalidTerm(*self))?,
126 )
127 })),
128 Handle::Bin(bs) => {
129 let b = &bs.bytes[..bs.len as usize];
130 Ok(View::Bin(b))
131 }
132 Handle::BinRef(br) => Ok(View::Bin(
133 arena
134 .byte_slice(br)
135 .map_err(|_| TermError::InvalidTerm(*self))?,
136 )),
137 Handle::FuncRef(fr) => {
138 let slice = arena
139 .term_slice(fr)
140 .map_err(|_| TermError::InvalidTerm(*self))?;
141 let functor = &slice[0];
143 let args = &slice[1..];
144 Ok(View::Func(arena, functor, args))
145 }
146 Handle::ListRef(lr) => {
147 let slice = arena
148 .term_slice(lr)
149 .map_err(|_| TermError::InvalidTerm(*self))?;
150 Ok(View::List(arena, slice, &Term::NIL))
151 }
152 Handle::ListCRef(lr) => {
153 let slice = arena
154 .term_slice(lr)
155 .map_err(|_| TermError::InvalidTerm(*self))?;
156 let last = slice.len() - 1;
157 Ok(View::List(arena, &slice[..last], &slice[last]))
158 }
159 Handle::TupleRef(tr) => {
160 let slice = arena
161 .term_slice(tr)
162 .map_err(|_| TermError::InvalidTerm(*self))?;
163 Ok(View::Tuple(arena, slice))
164 }
165 }
166 }
167}
168
169impl Arena {
170 #[inline]
175 pub fn view<'a>(&'a self, term: &'a Term) -> Result<View<'a>, TermError> {
176 term.view(self)
177 }
178}
179
180impl<'a> PartialEq for View<'a> {
181 fn eq(&self, other: &Self) -> bool {
182 let order_a = kind_order(self);
183 let order_b = kind_order(other);
184 if order_a != order_b {
185 return false;
186 }
187 match (self, other) {
188 (
190 View::Int(_) | View::Real(_) | View::Date(_),
191 View::Int(_) | View::Real(_) | View::Date(_),
192 ) => {
193 let a = numeric_value(self);
194 let b = numeric_value(other);
195 a == b
196 }
197 (View::Var(a), View::Var(b)) => a == b,
199 (View::Atom(a), View::Atom(b)) => a == b,
201 (View::Str(a), View::Str(b)) => a == b,
203 (View::Bin(a), View::Bin(b)) => a == b,
205 (View::Func(arena_a, functor_a, args_a), View::Func(arena_b, functor_b, args_b)) => {
207 if args_a.len() != args_b.len() {
208 return false;
209 }
210 if functor_a != functor_b {
211 return false;
212 }
213 args_a.iter().zip(args_b.iter()).all(|(a, b)| {
214 a.view(arena_a).expect("arena mismatch")
215 == b.view(arena_b).expect("arena mismatch")
216 })
217 }
218 (View::List(arena_a, args_a, tail_a), View::List(arena_b, args_b, tail_b)) => {
219 if args_a.len() != args_b.len() {
220 return false;
221 }
222 args_a.iter().zip(args_b.iter()).all(|(a, b)| {
223 a.view(arena_a).expect("arena mismatch")
224 == b.view(arena_b).expect("arena mismatch")
225 }) && tail_a.view(arena_a).expect("arena mismatch")
226 == tail_b.view(arena_b).expect("arena mismatch")
227 }
228 (View::Tuple(arena_a, args_a), View::Tuple(arena_b, args_b)) => {
229 if args_a.len() != args_b.len() {
230 return false;
231 }
232 args_a.iter().zip(args_b.iter()).all(|(a, b)| {
233 a.view(arena_a).expect("arena mismatch")
234 == b.view(arena_b).expect("arena mismatch")
235 })
236 }
237 _ => unreachable!(),
238 }
239 }
240}
241
242impl<'a> Eq for View<'a> {}
243
244impl core::cmp::PartialOrd for View<'_> {
245 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
246 Some(self.cmp(other))
247 }
248}
249
250impl core::cmp::Ord for View<'_> {
251 fn cmp(&self, other: &Self) -> Ordering {
252 let order_a = kind_order(self);
253 let order_b = kind_order(other);
254 if order_a != order_b {
255 return order_a.cmp(&order_b);
256 }
257 match (self, other) {
258 (
260 View::Int(_) | View::Real(_) | View::Date(_),
261 View::Int(_) | View::Real(_) | View::Date(_),
262 ) => {
263 let a = numeric_value(self);
264 let b = numeric_value(other);
265 a.total_cmp(&b)
266 }
267 (View::Var(a), View::Var(b)) => a.cmp(b),
269 (View::Atom(a), View::Atom(b)) => a.cmp(b),
271 (View::Str(a), View::Str(b)) => a.cmp(b),
273 (View::Bin(a), View::Bin(b)) => a.cmp(b),
275 (View::Func(arena_a, functor_a, args_a), View::Func(arena_b, functor_b, args_b)) => {
277 let ord = args_a.len().cmp(&args_b.len());
278 if ord != Ordering::Equal {
279 return ord;
280 }
281 let ord = functor_a
282 .view(arena_a)
283 .expect("arena mismatch")
284 .cmp(&functor_b.view(arena_b).expect("arena mismatch"));
285 if ord != Ordering::Equal {
286 return ord;
287 }
288 for (arg_a, arg_b) in args_a.iter().zip(args_b.iter()).map(|(a, b)| {
289 (
290 a.view(arena_a).expect("arena mismatch"),
291 b.view(arena_b).expect("arena mismatch"),
292 )
293 }) {
294 let ord = arg_a.cmp(&arg_b);
295 if ord != Ordering::Equal {
296 return ord;
297 }
298 }
299 Ordering::Equal
300 }
301 (View::List(arena_a, args_a, tail_a), View::List(arena_b, args_b, tail_b)) => {
302 let ord = args_a.len().cmp(&args_b.len());
303 if ord != Ordering::Equal {
304 return ord;
305 }
306 for (arg_a, arg_b) in args_a.iter().zip(args_b.iter()).map(|(a, b)| {
307 (
308 a.view(arena_a).expect("arena mismatch"),
309 b.view(arena_b).expect("arena mismatch"),
310 )
311 }) {
312 let ord = arg_a.cmp(&arg_b);
313 if ord != Ordering::Equal {
314 return ord;
315 }
316 }
317 tail_a
318 .view(arena_a)
319 .expect("arena mismatch")
320 .cmp(&tail_b.view(arena_b).expect("arena mismatch"))
321 }
322 (View::Tuple(arena_a, args_a), View::Tuple(arena_b, args_b)) => {
323 let ord = args_a.len().cmp(&args_b.len());
324 if ord != Ordering::Equal {
325 return ord;
326 }
327 for (arg_a, arg_b) in args_a.iter().zip(args_b.iter()).map(|(a, b)| {
328 (
329 a.view(arena_a).expect("arena mismatch"),
330 b.view(arena_b).expect("arena mismatch"),
331 )
332 }) {
333 let ord = arg_a.cmp(&arg_b);
334 if ord != Ordering::Equal {
335 return ord;
336 }
337 }
338 Ordering::Equal
339 }
340
341 _ => unreachable!(),
342 }
343 }
344}
345
346fn kind_order(t: &View) -> u8 {
350 match t {
351 View::Var(_) => 0,
352 View::Int(_) => 1,
353 View::Date(_) => 2,
354 View::Real(_) => 3,
355 View::Atom(_) => 4,
356 View::Str(_) => 5,
357 View::Func(_, _, _) => 6,
358 View::Tuple(_, _) => 7,
359 View::List(_, _, _) => 8,
360 View::Bin(_) => 9,
361 }
362}
363
364fn numeric_value(t: &View) -> f64 {
369 match t {
370 View::Int(i) => *i as f64,
371 View::Real(f) => *f,
372 View::Date(d) => *d as f64,
373 _ => unreachable!(),
374 }
375}
376
377#[cfg(test)]
378mod tests {
379 use super::*;
380
381 #[test]
382 fn view_size_is_40_bytes() {
383 assert_eq!(core::mem::size_of::<View>(), 40);
384 }
385
386 #[test]
387 fn option_view_size_is_40_bytes() {
388 assert_eq!(core::mem::size_of::<Option<View>>(), 40);
389 }
390}