use crate::global::RC;
use nar_dev_utils::RefCount;
use serde::{Deserialize, Serialize};
pub type Serial = u64;
pub trait RcSerial: Sized + Clone {
fn rc_serial(&self) -> Serial;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SerialRef<T: RcSerial> {
rc: RC<T>,
serial: Serial,
}
impl<T: RcSerial> SerialRef<T> {
fn get_serial_rc(inner: &RC<T>) -> Serial {
inner.get_().rc_serial()
}
pub fn new(inner: T) -> Self {
let rc = RC::new_(inner);
let serial = Self::get_serial_rc(&rc) as Serial;
Self { rc, serial }
}
fn serial(&self) -> Serial {
self.serial
}
fn inner_serial(&self) -> Serial {
self.get_().rc_serial()
}
fn sync_serial(&mut self) {
self.serial = self.inner_serial();
}
}
impl<T: RcSerial> RefCount<T> for SerialRef<T> {
type Ref<'r> = <RC<T> as RefCount<T>>::Ref<'r> where T: 'r;
type RefMut<'r> = <RC<T> as RefCount<T>>::RefMut<'r> where T: 'r;
fn new_(t: T) -> Self {
Self::new(t)
}
#[inline(always)]
fn get_<'r, 's: 'r>(&'s self) -> Self::Ref<'r> {
self.rc.get_()
}
#[inline(always)]
fn mut_<'r, 's: 'r>(&'s mut self) -> Self::RefMut<'r> {
self.rc.mut_()
}
fn n_strong_(&self) -> usize {
self.rc.n_strong_()
}
fn n_weak_(&self) -> usize {
self.rc.n_weak_()
}
fn ref_eq(&self, other: &Self) -> bool {
self.rc.ref_eq(&other.rc)
}
}
impl<T: RcSerial> From<T> for SerialRef<T> {
fn from(value: T) -> Self {
Self::new(value)
}
}
pub trait IterInnerRcSelf: RcSerial {
fn iter_inner_rc_self(&mut self) -> impl Iterator<Item = &mut SerialRef<Self>>;
}
impl<'t, T: RcSerial + IterInnerRcSelf + 't> SerialRef<T> {
pub fn unify_rcs(refs: impl IntoIterator<Item = &'t mut Self>) {
use std::collections::HashMap;
let mut serial_map: HashMap<Serial, Self> = HashMap::new();
let mut deal_serial = move |task_rc: &mut Self| {
match serial_map.get(&task_rc.serial()) {
Some(rc) => {
if !task_rc.ref_eq(rc) {
*task_rc = rc.clone()
}
}
None => {
let serial_to_identify = task_rc.serial();
task_rc.sync_serial();
serial_map.insert(serial_to_identify, task_rc.clone());
}
}
};
for task_rc in refs {
for inner_rc in task_rc.mut_().iter_inner_rc_self() {
deal_serial(inner_rc)
}
deal_serial(task_rc)
}
}
}
#[cfg(test)]
pub(crate) mod tests_serial_rc {
use super::*;
impl<T: RcSerial> SerialRef<T> {
pub fn serial_(&self) -> Serial {
self.serial
}
pub fn get_serial_(inner: &T) -> Serial {
inner as *const T as Serial
}
pub fn inner_serial_(&self) -> Serial {
self.get_().rc_serial()
}
pub fn sync_serial_(&mut self) {
self.serial = self.inner_serial();
}
pub fn with_serial(serial: Serial, inner: T) -> Self {
Self {
rc: RC::new_(inner),
serial,
}
}
pub fn is_synced_serial(&self) -> bool {
self.serial == self.inner_serial()
}
}
}