use super::fli;
use super::result::*;
use super::term::*;
use crate::{term_getable, term_putable, unifiable};
pub struct Record {
record: fli::record_t,
}
impl Record {
pub fn from_term(term: &Term) -> Record {
term.assert_term_handling_possible();
unsafe {
let record = fli::PL_record(term.term_ptr());
Record { record }
}
}
pub fn recorded(&self, term: &Term) -> PrologResult<()> {
term.assert_term_handling_possible();
unsafe { into_prolog_result(fli::PL_recorded(self.record, term.term_ptr()) != 0) }
}
}
impl Clone for Record {
fn clone(&self) -> Self {
unsafe {
let new_record = fli::PL_duplicate_record(self.record);
assert!(self.record == new_record);
Record { record: new_record }
}
}
}
impl Drop for Record {
fn drop(&mut self) {
unsafe {
fli::PL_erase(self.record);
}
}
}
term_putable! {
(self: Record, term) => {
self.recorded(term).expect("expected record to be putable");
}
}
term_getable! {
(Record, term) => {
Some(Record::from_term(term))
}
}
unifiable! {
(self:Record, term) => {
unsafe {
let extra_term = fli::PL_new_term_ref();
fli::PL_recorded(self.record, extra_term);
let result = fli::PL_unify(term.term_ptr(), extra_term);
fli::PL_reset_term_refs(extra_term);
result != 0
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::context::*;
use crate::engine::*;
use crate::term;
#[test]
fn record_and_put() {
let engine = Engine::new();
let activation = engine.activate();
let context: Context<_> = activation.into();
let term1 = term! {context: foo(bar(baz, quux))}.unwrap();
let record = term1.record();
let term2 = context.new_term_ref();
term2.put(&record).unwrap();
assert!(term1 == term2);
}
#[test]
fn record_and_put_var() {
let engine = Engine::new();
let activation = engine.activate();
let context: Context<_> = activation.into();
let term1 = term! {context: foo(bar(baz, _))}.unwrap();
let record = term1.record();
let term2 = context.new_term_ref();
term2.put(&record).unwrap();
assert!(term1 != term2);
term1.unify(term2).unwrap();
}
#[test]
fn record_get_and_put() {
let engine = Engine::new();
let activation = engine.activate();
let context: Context<_> = activation.into();
let term1 = term! {context: foo(bar(baz, quux))}.unwrap();
let record: Record = term1.get().unwrap();
let term2 = context.new_term_ref();
term2.put(&record).unwrap();
assert!(term1 == term2);
}
#[test]
fn record_and_put_on_other_engine() {
let record: Record;
{
let engine = Engine::new();
let activation = engine.activate();
let context: Context<_> = activation.into();
let term = term! {context: foo(bar(baz, quux))}.unwrap();
record = term.record();
}
let engine = Engine::new();
let activation = engine.activate();
let context: Context<_> = activation.into();
let term1 = term! {context: foo(bar(baz, quux))}.unwrap();
let term2 = context.new_term_ref();
term2.put(&record).unwrap();
assert!(term1 == term2);
}
#[test]
fn record_clone_drop_put() {
let engine = Engine::new();
let activation = engine.activate();
let context: Context<_> = activation.into();
let term1 = term! {context: foo(bar(baz, quux))}.unwrap();
let record1 = term1.record();
let record2 = record1.clone();
let record3 = record2.clone();
std::mem::drop(record1);
std::mem::drop(record2);
let term2 = context.new_term_ref();
term2.put(&record3).unwrap();
assert!(term1 == term2);
}
#[test]
fn record_unify_self() {
let engine = Engine::new();
let activation = engine.activate();
let context: Context<_> = activation.into();
let term = term! {context: foo(bar(baz, quux))}.unwrap();
let record = term.record();
term.unify(&record).unwrap();
}
#[test]
fn record_unify_var() {
let engine = Engine::new();
let activation = engine.activate();
let context: Context<_> = activation.into();
let term1 = term! {context: foo(bar(baz, quux))}.unwrap();
let record = term1.record();
let term2 = context.new_term_ref();
term2.unify(&record).unwrap();
}
#[test]
fn record_unify_dif_fails() {
let engine = Engine::new();
let activation = engine.activate();
let context: Context<_> = activation.into();
let term1 = term! {context: foo(bar(baz, quux))}.unwrap();
let record = term1.record();
let term2 = term! {context: something(completely(different))}.unwrap();
assert!(!attempt(term2.unify(&record)).unwrap());
}
}