use super::{TLink, TLinkType, TLinkage, TermLink, TermLinkTemplate};
use crate::{
entity::{BudgetValue, Item, RCTask, Sentence, ShortFloat, Task, Token},
global::ClockTime,
inference::{Budget, Evidential},
parameters::DEFAULT_PARAMETERS,
util::ToDisplayAndBrief,
};
use nar_dev_utils::{join, RefCount};
use serde::{Deserialize, Serialize};
use std::ops::{Deref, DerefMut};
#[derive(Debug, Serialize, Deserialize)]
pub struct TaskLink {
inner: TLinkage<RCTask>,
token: Token,
recorded_links: Box<[(String, ClockTime)]>,
n_recorded_term_links: usize,
}
impl TaskLink {
pub(in crate::entity) fn target_rc_ref(&self) -> &RCTask {
&self.inner.target
}
pub(in crate::entity) fn target_rc_ref_mut(&mut self) -> &mut RCTask {
&mut self.inner.target
}
pub fn target_rc<'r, 's: 'r>(&'s self) -> impl Deref<Target = RCTask> + 'r {
&self.inner.target
}
pub fn target_rc_mut<'r, 's: 'r>(&'s mut self) -> impl DerefMut<Target = RCTask> + 'r {
&mut self.inner.target
}
}
impl Budget for TaskLink {
fn priority(&self) -> ShortFloat {
self.token.priority()
}
fn __priority_mut(&mut self) -> &mut ShortFloat {
self.token.__priority_mut()
}
fn durability(&self) -> ShortFloat {
self.token.durability()
}
fn __durability_mut(&mut self) -> &mut ShortFloat {
self.token.__durability_mut()
}
fn quality(&self) -> ShortFloat {
self.token.quality()
}
fn __quality_mut(&mut self) -> &mut ShortFloat {
self.token.__quality_mut()
}
}
impl Item for TaskLink {
fn key(&self) -> &String {
self.token.key()
}
}
impl TLink<Task> for TaskLink {
fn target<'r, 's: 'r>(&'s self) -> impl Deref<Target = Task> + 'r {
self.inner.target.get_()
}
fn target_mut<'r, 's: 'r>(&'s mut self) -> impl DerefMut<Target = Task> + 'r {
self.inner.target.mut_()
}
fn link_type(&self) -> TLinkType {
self.inner.link_type()
}
fn indexes(&self) -> &[usize] {
self.inner.indexes()
}
}
impl TaskLink {
const RECORD_LENGTH: usize = DEFAULT_PARAMETERS.term_link_record_length;
fn new(
target_rc: RCTask,
budget: BudgetValue,
link_type: TLinkType,
indexes: impl Into<Box<[usize]>>,
record_length: usize,
) -> Self {
let indexes = indexes.into();
let key = Self::generate_key_for_task_link(&target_rc.get_(), link_type, &indexes);
let token = Token::new(key, budget);
let inner = TLinkage::new_direct(target_rc, link_type, indexes);
let recorded_links = vec![(String::default(), 0); record_length].into_boxed_slice();
Self {
inner,
token,
recorded_links,
n_recorded_term_links: 0,
}
}
fn generate_key_for_task_link(
target: &Task,
link_type: TLinkType,
indexes: &[usize],
) -> String {
let key = Self::generate_key_base(link_type, indexes);
join! {
=> key
=> target.key()
}
}
fn with_default_record_len(
target_rc: RCTask,
budget: BudgetValue,
link_type: TLinkType,
indexes: impl Into<Box<[usize]>>,
) -> Self {
Self::new(target_rc, budget, link_type, indexes, Self::RECORD_LENGTH)
}
pub fn from_template(
target_rc: RCTask,
template: &TermLinkTemplate,
budget: BudgetValue,
) -> Self {
let indexes = template.indexes().to_vec().into_boxed_slice();
Self::with_default_record_len(target_rc, budget, template.link_type(), indexes)
}
pub fn new_self(target_rc: RCTask) -> Self {
let target_ref = target_rc.get_();
let budget = BudgetValue::from_other(&*target_ref);
drop(target_ref);
let indexes = vec![].into_boxed_slice();
Self::with_default_record_len(target_rc, budget, TLinkType::SELF, indexes)
}
pub fn novel(&mut self, term_link: &TermLink, current_time: ClockTime) -> bool {
{
let b_term = &*term_link.target();
let t_term = self.target();
if b_term == t_term.content() {
return false;
}
}
let link_key = term_link.key();
for i in 0..self.n_recorded_term_links {
let existed_i = i % self.recorded_links.len();
let (existed_key, existed_time) = &self.recorded_links[existed_i];
if link_key == existed_key {
if current_time < existed_time + self.recorded_links.len() {
return false;
}
else {
self.recorded_links[existed_i].1 = current_time;
return true;
}
}
}
let next = self.n_recorded_term_links % self.recorded_links.len();
self.recorded_links[next] = (link_key.clone(), current_time);
if self.n_recorded_term_links < self.recorded_links.len() {
self.n_recorded_term_links += 1;
}
true
}
}
impl ToDisplayAndBrief for TaskLink {
fn to_display(&self) -> String {
join! {
=> self.token.budget_to_display()
=> " "
=> self.key()
=> " "
=> self.target().stamp_to_display()
}
}
}