use std::sync::Arc;
use crate::io::resource::{FD_RESOURCE_WORDS, FdInner, write_fd_resource};
use crate::term::Term;
use crate::term::boxed::{
write_bigint, write_cons, write_external_pid, write_external_reference, write_float, write_map,
write_reference, write_tuple,
};
use crate::term::shared_binary::{alloc_binary, alloc_binary_word_count};
use super::ProcessContext;
impl ProcessContext<'_> {
pub fn alloc_tuple(&mut self, elements: &[Term]) -> Result<Term, Term> {
let words = 1 + elements.len();
if self.process.is_none() {
let heap = self.alloc_words(words)?;
return write_tuple(heap, elements)
.ok_or_else(|| Term::atom(crate::atom::Atom::BADARG));
}
self.with_rooted(elements, |context, roots| {
context.ensure_heap_space(words)?;
let mut current = Vec::with_capacity(roots.len);
for index in 0..roots.len {
current.push(context.rooted(roots, index)?);
}
let heap = context.alloc_words_prereserved(words)?;
write_tuple(heap, ¤t).ok_or_else(|| Term::atom(crate::atom::Atom::BADARG))
})
}
pub fn alloc_tuple_prereserved(&mut self, elements: &[Term]) -> Result<Term, Term> {
let words = 1 + elements.len();
let heap = self.alloc_words_prereserved(words)?;
write_tuple(heap, elements).ok_or_else(|| Term::atom(crate::atom::Atom::BADARG))
}
pub fn alloc_reference(&mut self, id: u64) -> Result<Term, Term> {
let heap = self.alloc_words(2)?;
write_reference(heap, id).ok_or_else(|| Term::atom(crate::atom::Atom::BADARG))
}
pub fn alloc_reference_prereserved(&mut self, id: u64) -> Result<Term, Term> {
let heap = self.alloc_words_prereserved(2)?;
write_reference(heap, id).ok_or_else(|| Term::atom(crate::atom::Atom::BADARG))
}
pub fn alloc_external_pid(
&mut self,
node: crate::atom::Atom,
pid_number: u64,
serial: u64,
) -> Result<Term, Term> {
let heap = self.alloc_words(4)?;
write_external_pid(heap, node, pid_number, serial)
.ok_or_else(|| Term::atom(crate::atom::Atom::BADARG))
}
pub fn alloc_external_pid_prereserved(
&mut self,
node: crate::atom::Atom,
pid_number: u64,
serial: u64,
) -> Result<Term, Term> {
let heap = self.alloc_words_prereserved(4)?;
write_external_pid(heap, node, pid_number, serial)
.ok_or_else(|| Term::atom(crate::atom::Atom::BADARG))
}
pub fn alloc_external_reference(
&mut self,
node: crate::atom::Atom,
id: u64,
) -> Result<Term, Term> {
let heap = self.alloc_words(3)?;
write_external_reference(heap, node, id)
.ok_or_else(|| Term::atom(crate::atom::Atom::BADARG))
}
pub fn alloc_external_reference_prereserved(
&mut self,
node: crate::atom::Atom,
id: u64,
) -> Result<Term, Term> {
let heap = self.alloc_words_prereserved(3)?;
write_external_reference(heap, node, id)
.ok_or_else(|| Term::atom(crate::atom::Atom::BADARG))
}
pub fn alloc_cons(&mut self, head: Term, tail: Term) -> Result<Term, Term> {
if self.process.is_none() {
let heap = self.alloc_words(2)?;
return write_cons(heap, head, tail)
.ok_or_else(|| Term::atom(crate::atom::Atom::BADARG));
}
self.with_rooted(&[head, tail], |context, roots| {
context.ensure_heap_space(2)?;
let head = context.rooted(roots, 0)?;
let tail = context.rooted(roots, 1)?;
let heap = context.alloc_words_prereserved(2)?;
write_cons(heap, head, tail).ok_or_else(|| Term::atom(crate::atom::Atom::BADARG))
})
}
pub fn alloc_float(&mut self, value: f64) -> Result<Term, Term> {
let heap = self.alloc_words(2)?;
write_float(heap, value).ok_or_else(|| Term::atom(crate::atom::Atom::BADARG))
}
pub fn alloc_binary(&mut self, bytes: &[u8]) -> Result<Term, Term> {
let words = alloc_binary_word_count(bytes.len());
let heap = self.alloc_words(words)?;
alloc_binary(heap, bytes).ok_or_else(|| Term::atom(crate::atom::Atom::BADARG))
}
pub fn alloc_fd_resource(&mut self, fd_inner: Arc<FdInner>) -> Result<Term, Term> {
let heap = self.alloc_words(FD_RESOURCE_WORDS)?;
write_fd_resource(heap, fd_inner).ok_or_else(|| Term::atom(crate::atom::Atom::BADARG))
}
pub fn alloc_bigint(&mut self, negative: bool, limbs: &[u64]) -> Result<Term, Term> {
let words = 3 + limbs.len();
let heap = self.alloc_words(words)?;
write_bigint(heap, negative, limbs).ok_or_else(|| Term::atom(crate::atom::Atom::BADARG))
}
pub fn alloc_list(&mut self, elements: &[Term]) -> Result<Term, Term> {
self.alloc_list_with_tail(elements, Term::NIL)
}
pub fn alloc_list_with_tail(&mut self, elements: &[Term], tail: Term) -> Result<Term, Term> {
if self.process.is_none() {
let mut tail = tail;
for element in elements.iter().rev().copied() {
let heap = self.alloc_words_prereserved(2)?;
tail = write_cons(heap, element, tail)
.ok_or_else(|| Term::atom(crate::atom::Atom::BADARG))?;
}
return Ok(tail);
}
let mut rooted = Vec::with_capacity(elements.len() + 1);
rooted.extend_from_slice(elements);
rooted.push(tail);
self.with_rooted(&rooted, |context, roots| {
context.ensure_heap_space(elements.len() * 2)?;
let mut tail = context.rooted(roots, elements.len())?;
for index in (0..elements.len()).rev() {
let element = context.rooted(roots, index)?;
let heap = context.alloc_words_prereserved(2)?;
tail = write_cons(heap, element, tail)
.ok_or_else(|| Term::atom(crate::atom::Atom::BADARG))?;
}
Ok(tail)
})
}
pub fn alloc_cons_prereserved(&mut self, head: Term, tail: Term) -> Result<Term, Term> {
let heap = self.alloc_words_prereserved(2)?;
write_cons(heap, head, tail).ok_or_else(|| Term::atom(crate::atom::Atom::BADARG))
}
pub fn alloc_map(&mut self, keys: &[Term], values: &[Term]) -> Result<Term, Term> {
let words = 2 + keys.len() + values.len();
if self.process.is_none() {
let heap = self.alloc_words(words)?;
return write_map(heap, keys, values)
.ok_or_else(|| Term::atom(crate::atom::Atom::BADARG));
}
let mut rooted = Vec::with_capacity(keys.len() + values.len());
rooted.extend_from_slice(keys);
rooted.extend_from_slice(values);
self.with_rooted(&rooted, |context, roots| {
context.ensure_heap_space(words)?;
let mut current_keys = Vec::with_capacity(keys.len());
let mut current_values = Vec::with_capacity(values.len());
for index in 0..keys.len() {
current_keys.push(context.rooted(roots, index)?);
}
for index in 0..values.len() {
current_values.push(context.rooted(roots, keys.len() + index)?);
}
let heap = context.alloc_words_prereserved(words)?;
write_map(heap, ¤t_keys, ¤t_values)
.ok_or_else(|| Term::atom(crate::atom::Atom::BADARG))
})
}
pub fn alloc_map_prereserved(&mut self, keys: &[Term], values: &[Term]) -> Result<Term, Term> {
let words = 2 + keys.len() + values.len();
let heap = self.alloc_words_prereserved(words)?;
write_map(heap, keys, values).ok_or_else(|| Term::atom(crate::atom::Atom::BADARG))
}
}