1use crate::{InternalTermError, IntoTerm, OperDefs, Slice, Term, TermError, View};
8
9#[derive(Default, Clone, Debug)]
52pub struct Arena {
53 pub(crate) arena_id: ArenaID,
55
56 pub(crate) current_epoch: usize,
59
60 pub(crate) epoch_ids: [EpochID; MAX_LIVE_EPOCHS],
66
67 pub(crate) bytes: Vec<u8>,
70
71 pub(crate) byte_start_by_epoch: [usize; MAX_LIVE_EPOCHS],
74
75 pub(crate) terms: Vec<Term>,
81
82 pub(crate) term_start_by_epoch: [usize; MAX_LIVE_EPOCHS],
85
86 pub(crate) opers: OperDefs,
88}
89
90pub const MAX_LIVE_EPOCHS: usize = 8;
91
92#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
93pub struct EpochID(pub(crate) u32); #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
96pub struct ArenaID(pub(crate) u32); #[derive(Debug, Clone, Copy)]
99pub struct ArenaStats {
100 pub current_epoch: EpochID,
101 pub bytes_len: usize,
102 pub terms_len: usize,
103}
104
105impl Arena {
106 pub fn with_capacity(bytes_capacity: usize, terms_capacity: usize) -> Self {
108 let mut epoch_ids = [EpochID(0); MAX_LIVE_EPOCHS];
109 epoch_ids[0] = EpochID(rand::random());
110
111 Self {
112 arena_id: ArenaID(rand::random()),
113 current_epoch: 0,
114 epoch_ids,
115 bytes: Vec::with_capacity(bytes_capacity),
116 byte_start_by_epoch: [0; MAX_LIVE_EPOCHS],
117 terms: Vec::with_capacity(terms_capacity),
118 term_start_by_epoch: [0; MAX_LIVE_EPOCHS],
119 opers: OperDefs::new(),
120 }
121 }
122
123 pub fn new() -> Self {
125 Self::with_capacity(4096, 1024)
126 }
127
128 pub fn try_with_default_opers() -> Result<Self, TermError> {
131 let mut arena = Self::new();
132 arena.define_default_opers()?;
133 Ok(arena)
134 }
135
136 pub fn stats(&self) -> ArenaStats {
138 ArenaStats {
139 current_epoch: self.epoch_ids[self.current_epoch],
140 bytes_len: self.bytes.len(),
141 terms_len: self.terms.len(),
142 }
143 }
144
145 pub fn current_epoch(&self) -> EpochID {
147 self.epoch_ids[self.current_epoch]
148 }
149
150 pub fn begin_epoch(&mut self) -> Result<EpochID, TermError> {
152 let new_epoch = self.current_epoch + 1;
153 if new_epoch >= MAX_LIVE_EPOCHS {
154 return Err(TermError::LiveEpochsExceeded);
155 }
156 self.epoch_ids[new_epoch] = EpochID(rand::random());
157 self.byte_start_by_epoch[new_epoch] = self.bytes.len();
158 self.term_start_by_epoch[new_epoch] = self.terms.len();
159 self.current_epoch = new_epoch;
160 Ok(self.epoch_ids[new_epoch])
161 }
162
163 pub fn clear(&mut self) -> Result<(), TermError> {
166 self.truncate(self.epoch_ids[0])
167 }
168
169 pub fn truncate_current(&mut self) -> Result<(), TermError> {
172 self.truncate(self.epoch_ids[self.current_epoch])
173 }
174
175 pub fn truncate(&mut self, epoch_id: EpochID) -> Result<(), TermError> {
178 let epoch = self
179 .epoch_index(epoch_id)
180 .map_err(|_| TermError::InvalidEpoch(epoch_id))?;
181 self.bytes.truncate(self.byte_start_by_epoch[epoch]);
182 self.terms.truncate(self.term_start_by_epoch[epoch]);
183 self.current_epoch = epoch;
184 Ok(())
185 }
186
187 #[inline]
189 fn epoch_index(&self, epoch_id: EpochID) -> Result<usize, InternalTermError> {
190 let Some(epoch) = self.epoch_ids[..=self.current_epoch]
191 .iter()
192 .position(|&id| id == epoch_id)
193 else {
194 return Err(InternalTermError::InvalidEpoch(epoch_id));
195 };
196 Ok(epoch)
197 }
198
199 #[inline]
202 fn verify_byte_slice(&self, slice: &Slice) -> Result<(), InternalTermError> {
203 let epoch = self.epoch_index(slice.epoch_id)?;
204 let epoch_start = self.byte_start_by_epoch[epoch];
205 let epoch_end = if epoch == self.current_epoch {
206 self.bytes.len()
207 } else {
208 self.byte_start_by_epoch[epoch + 1]
209 };
210 if (slice.index as usize) < epoch_start
211 || (slice.index as usize) + (slice.len as usize) > epoch_end
212 {
213 return Err(InternalTermError::InvalidSlice(*slice));
214 }
215 Ok(())
216 }
217
218 #[inline]
221 fn verify_term_slice(&self, slice: &Slice) -> Result<(), InternalTermError> {
222 let epoch = self.epoch_index(slice.epoch_id)?;
223 let epoch_start = self.term_start_by_epoch[epoch];
224 let epoch_end = if epoch == self.current_epoch {
225 self.terms.len()
226 } else {
227 self.term_start_by_epoch[epoch + 1]
228 };
229 if (slice.index as usize) < epoch_start
230 || (slice.index as usize) + (slice.len as usize) > epoch_end
231 {
232 return Err(InternalTermError::InvalidSlice(*slice));
233 }
234 Ok(())
235 }
236
237 #[inline]
239 pub fn term<'a, T: IntoTerm>(&'a mut self, value: T) -> Term {
240 value.into_term(self)
241 }
242
243 #[inline]
247 pub fn int(&mut self, i: impl Into<i64>) -> Term {
248 Term::int(i)
249 }
250
251 #[inline]
254 pub fn real(&mut self, r: impl Into<f64>) -> Term {
255 Term::real(r)
256 }
257
258 #[inline]
261 pub fn date(&mut self, ms: impl Into<i64>) -> Term {
262 Term::date(ms)
263 }
264
265 #[inline]
270 pub fn atom(&mut self, name: impl AsRef<str>) -> Term {
271 Term::atom(self, name)
272 }
273
274 #[inline]
279 pub fn var(&mut self, name: impl AsRef<str>) -> Term {
280 Term::var(self, name)
281 }
282
283 #[inline]
288 pub fn str(&mut self, s: impl AsRef<str>) -> Term {
289 Term::str(self, s)
290 }
291
292 #[inline]
296 pub fn bin(&mut self, bytes: impl AsRef<[u8]>) -> Term {
297 Term::bin(self, bytes)
298 }
299
300 #[inline]
306 pub fn func(
307 &mut self,
308 functor: impl AsRef<str>,
309 args: impl IntoIterator<Item = impl IntoTerm>,
310 ) -> Term {
311 Term::func(self, functor, args)
312 }
313
314 #[inline]
319 pub fn funcv(
320 &mut self,
321 terms: impl IntoIterator<Item = impl IntoTerm>,
322 ) -> Result<Term, TermError> {
323 Term::funcv(self, terms)
324 }
325
326 #[inline]
329 pub fn list(&mut self, terms: impl IntoIterator<Item = impl IntoTerm>) -> Term {
330 Term::list(self, terms)
331 }
332
333 #[inline]
336 pub fn listc(
337 &mut self,
338 terms: impl IntoIterator<Item = impl IntoTerm>,
339 tail: impl IntoTerm,
340 ) -> Term {
341 Term::listc(self, terms, tail)
342 }
343
344 #[inline]
347 pub fn tuple(&mut self, terms: impl IntoIterator<Item = impl IntoTerm>) -> Term {
348 Term::tuple(self, terms)
349 }
350
351 pub const UNIT: Term = Term::UNIT;
355
356 pub const NIL: Term = Term::NIL;
360
361 #[inline]
365 pub fn name<'a>(&'a self, term: &'a Term) -> Result<&'a str, TermError> {
366 match self.view(term)? {
367 View::Var(name) | View::Atom(name) => Ok(name),
368 View::Func(ar, functor, _) => Ok(functor.atom_name(ar)?),
369 _ => Err(TermError::UnexpectedKind {
370 expected: "var, atom, func",
371 found: term.kind_name(),
372 }),
373 }
374 }
375
376 #[inline]
378 pub fn atom_name<'a>(&'a self, term: &'a Term) -> Result<&'a str, TermError> {
379 self.unpack_atom(term, &[])
380 }
381
382 #[inline]
384 pub fn var_name<'a>(&'a self, term: &'a Term) -> Result<&'a str, TermError> {
385 self.unpack_var(term, &[])
386 }
387
388 #[inline]
390 pub fn func_name<'a>(&'a self, term: &'a Term) -> Result<&'a str, TermError> {
391 let (functor, _) = self.unpack_func_any(term, &[])?;
392 self.atom_name(functor)
393 }
394
395 #[inline]
397 pub fn unpack_int(&self, term: &Term) -> Result<i64, TermError> {
398 match self.view(term)? {
399 View::Int(v) => Ok(v),
400 _ => Err(TermError::UnexpectedKind {
401 expected: "int",
402 found: term.kind_name(),
403 }),
404 }
405 }
406
407 #[inline]
409 pub fn unpack_real(&self, term: &Term) -> Result<f64, TermError> {
410 match self.view(term)? {
411 View::Real(v) => Ok(v),
412 _ => Err(TermError::UnexpectedKind {
413 expected: "real",
414 found: term.kind_name(),
415 }),
416 }
417 }
418
419 #[inline]
421 pub fn unpack_date(&self, term: &Term) -> Result<i64, TermError> {
422 match self.view(term)? {
423 View::Date(v) => Ok(v),
424 _ => Err(TermError::UnexpectedKind {
425 expected: "date",
426 found: term.kind_name(),
427 }),
428 }
429 }
430
431 #[inline]
433 pub fn unpack_str<'a>(&'a self, term: &'a Term) -> Result<&'a str, TermError> {
434 match self.view(term)? {
435 View::Str(v) => Ok(v),
436 _ => Err(TermError::UnexpectedKind {
437 expected: "str",
438 found: term.kind_name(),
439 }),
440 }
441 }
442
443 #[inline]
445 pub fn unpack_bin<'a>(&'a self, term: &'a Term) -> Result<&'a [u8], TermError> {
446 match self.view(term)? {
447 View::Bin(v) => Ok(v),
448 _ => Err(TermError::UnexpectedKind {
449 expected: "bin",
450 found: term.kind_name(),
451 }),
452 }
453 }
454
455 #[inline]
457 pub fn unpack_atom<'a>(
458 &'a self,
459 term: &'a Term,
460 allowed_names: &[&str],
461 ) -> Result<&'a str, TermError> {
462 match self.view(term)? {
463 View::Atom(name) => {
464 if !allowed_names.is_empty() && !allowed_names.contains(&name) {
465 return Err(TermError::UnexpectedName(*term));
466 }
467 Ok(name)
468 }
469 _ => Err(TermError::UnexpectedKind {
470 expected: "atom",
471 found: term.kind_name(),
472 }),
473 }
474 }
475
476 #[inline]
478 pub fn unpack_var<'a>(
479 &'a self,
480 term: &'a Term,
481 allowed_names: &[&str],
482 ) -> Result<&'a str, TermError> {
483 match self.view(term)? {
484 View::Var(name) => {
485 if !allowed_names.is_empty() && !allowed_names.contains(&name) {
486 return Err(TermError::UnexpectedName(*term));
487 }
488 Ok(name)
489 }
490 _ => Err(TermError::UnexpectedKind {
491 expected: "var",
492 found: term.kind_name(),
493 }),
494 }
495 }
496
497 #[inline]
501 pub fn unpack_func_any<'a>(
502 &'a self,
503 term: &'a Term,
504 allowed_names: &[&str],
505 ) -> Result<(&'a Term, &'a [Term]), TermError> {
506 match self.view(term)? {
507 View::Atom(name) => {
508 if !allowed_names.is_empty() && !allowed_names.contains(&name) {
509 return Err(TermError::UnexpectedName(*term));
510 }
511 Ok((term, &[] as &[Term]))
512 }
513 View::Func(_, functor, args) => {
514 if args.is_empty() {
515 return Err(TermError::InvalidTerm(*term));
516 }
517 if !allowed_names.is_empty() {
518 let name = self.atom_name(functor)?;
519 if !allowed_names.contains(&name) {
520 return Err(TermError::UnexpectedName(*term));
521 }
522 }
523 Ok((functor, args))
524 }
525 _ => Err(TermError::UnexpectedKind {
526 expected: "func",
527 found: term.kind_name(),
528 }),
529 }
530 }
531
532 #[inline]
536 pub fn unpack_func<'a, const ARITY: usize>(
537 &'a self,
538 term: &'a Term,
539 allowed_names: &[&str],
540 ) -> Result<(&'a Term, [Term; ARITY]), TermError> {
541 let (functor, args) = self.unpack_func_any(term, allowed_names)?;
542 if args.len() != ARITY {
543 return Err(TermError::UnexpectedArity {
544 expected: ARITY,
545 found: args.len(),
546 });
547 }
548 let arr: [_; ARITY] = args.try_into().unwrap();
549 return Ok((functor, arr));
550 }
551
552 #[inline]
555 pub fn unpack_list<'a>(&'a self, term: &'a Term) -> Result<(&'a [Term], &'a Term), TermError> {
556 match self.view(term)? {
557 View::Atom(_) if term == &Term::NIL => Ok((&[], &Term::NIL)),
558 View::List(_, terms, tail) => Ok((terms, tail)),
559 _ => Err(TermError::UnexpectedKind {
560 expected: "list",
561 found: term.kind_name(),
562 }),
563 }
564 }
565
566 #[inline]
569 pub fn unpack_tuple_any<'a>(&'a self, term: &'a Term) -> Result<&'a [Term], TermError> {
570 match self.view(term)? {
571 View::Atom(_) if *term == Term::UNIT => Ok(&[]),
572 View::Tuple(_, terms) => Ok(terms),
573 _ => Err(TermError::UnexpectedKind {
574 expected: "tuple",
575 found: term.kind_name(),
576 }),
577 }
578 }
579
580 #[inline]
583 pub fn unpack_tuple<const ARITY: usize>(
584 &self,
585 term: &Term,
586 ) -> Result<[Term; ARITY], TermError> {
587 let terms = self.unpack_tuple_any(term)?;
588 if terms.len() != ARITY {
589 return Err(TermError::UnexpectedArity {
590 expected: ARITY,
591 found: terms.len(),
592 });
593 }
594 let arr: [_; ARITY] = terms.try_into().unwrap();
595 return Ok(arr);
596 }
597
598 #[inline]
601 pub(crate) fn intern_str(&mut self, s: &str) -> Slice {
602 let index = self.bytes.len();
603 self.bytes.extend_from_slice(s.as_bytes());
604 let len = s.len();
605 Slice {
606 epoch_id: self.epoch_ids[self.current_epoch],
607 index: index as u32,
608 len: len as u32,
609 }
610 }
611
612 #[inline]
614 pub(crate) fn intern_bytes(&mut self, bytes: &[u8]) -> Slice {
615 let index = self.bytes.len();
616 self.bytes.extend_from_slice(bytes);
617 let len = bytes.len();
618 Slice {
619 epoch_id: self.epoch_ids[self.current_epoch],
620 index: index as u32,
621 len: len as u32,
622 }
623 }
624
625 #[inline]
627 pub(crate) fn intern_func(
628 &mut self,
629 functor: Term,
630 args: impl IntoIterator<Item = impl IntoTerm>,
631 ) -> Slice {
632 let index = self.terms.len();
633 self.terms.push(functor);
634 for x in args {
635 let t = x.into_term(self);
636 self.terms.push(t);
637 }
638 let len = self.terms.len() - index;
639 Slice {
640 epoch_id: self.epoch_ids[self.current_epoch],
641 index: index as u32,
642 len: len as u32,
643 }
644 }
645
646 #[inline]
648 pub(crate) fn intern_seq(&mut self, terms: impl IntoIterator<Item = impl IntoTerm>) -> Slice {
649 let index = self.terms.len();
650 for x in terms {
651 let t = x.into_term(self);
652 self.terms.push(t);
653 }
654 let len = self.terms.len() - index;
655 Slice {
656 epoch_id: self.epoch_ids[self.current_epoch],
657 index: index as u32,
658 len: len as u32,
659 }
660 }
661
662 #[inline]
664 pub(crate) fn intern_seq_plus_one(
665 &mut self,
666 terms: impl IntoIterator<Item = impl IntoTerm>,
667 tail: impl IntoTerm,
668 ) -> Slice {
669 let index = self.terms.len();
670 for x in terms {
671 let t = x.into_term(self);
672 self.terms.push(t);
673 }
674 let t = tail.into_term(self);
675 self.terms.push(t);
676 let len = self.terms.len() - index;
677 Slice {
678 epoch_id: self.epoch_ids[self.current_epoch],
679 index: index as u32,
680 len: len as u32,
681 }
682 }
683
684 #[inline]
688 pub(crate) fn byte_slice<'a>(&'a self, slice: &Slice) -> Result<&'a [u8], InternalTermError> {
689 self.verify_byte_slice(slice)?;
690 Ok(&self.bytes[(slice.index as usize)..((slice.index + slice.len) as usize)])
691 }
692
693 #[inline]
695 pub(crate) fn term_slice<'a>(&'a self, slice: &Slice) -> Result<&'a [Term], InternalTermError> {
696 self.verify_term_slice(slice)?;
697 Ok(&self.terms[(slice.index as usize)..((slice.index + slice.len) as usize)])
698 }
699}