use std::hash::Hasher;
use std::sync::{Arc, LazyLock};
use hugr::extension::prelude::{bool_t, qb_t};
use hugr::types::Type;
use tket_json_rs::register::ElementId as PytketRegister;
use crate::serialize::pytket::RegisterHash;
#[derive(Clone, Copy, Debug, derive_more::Display, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub(super) struct TrackedQubitId(#[display(transparent)] pub usize);
#[derive(Clone, Copy, Debug, derive_more::Display, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub(super) struct TrackedBitId(#[display(transparent)] pub usize);
#[derive(Debug, Clone, Eq, derive_more::Display)]
#[display("{reg}")]
pub struct TrackedQubit {
id: TrackedQubitId,
outdated: bool,
reg: Arc<PytketRegister>,
reg_hash: RegisterHash,
}
#[derive(Debug, Clone, Eq, derive_more::Display)]
#[display("{reg}")]
pub struct TrackedBit {
id: TrackedBitId,
outdated: bool,
reg: Arc<PytketRegister>,
reg_hash: RegisterHash,
}
impl TrackedQubit {
pub(super) fn new(id: TrackedQubitId, reg: Arc<PytketRegister>) -> Self {
let reg_hash = RegisterHash::from(reg.as_ref());
Self::new_with_hash(id, reg, reg_hash)
}
pub(super) fn new_with_hash(
id: TrackedQubitId,
reg: Arc<PytketRegister>,
reg_hash: RegisterHash,
) -> Self {
Self {
id,
outdated: false,
reg,
reg_hash,
}
}
pub fn pytket_register(&self) -> &PytketRegister {
&self.reg
}
pub fn pytket_register_arc(&self) -> Arc<PytketRegister> {
self.reg.clone()
}
pub fn ty(&self) -> Arc<Type> {
static QUBIT_TYPE: LazyLock<Arc<Type>> = LazyLock::new(|| qb_t().into());
QUBIT_TYPE.clone()
}
pub(super) fn id(&self) -> TrackedQubitId {
self.id
}
pub(super) fn reg_hash(&self) -> RegisterHash {
self.reg_hash
}
pub fn is_outdated(&self) -> bool {
self.outdated
}
pub(super) fn mark_outdated(&mut self) {
self.outdated = true;
}
}
impl TrackedBit {
pub(super) fn new(id: TrackedBitId, reg: Arc<PytketRegister>) -> Self {
let reg_hash = RegisterHash::from(reg.as_ref());
Self::new_with_hash(id, reg, reg_hash)
}
pub(super) fn new_with_hash(
id: TrackedBitId,
reg: Arc<PytketRegister>,
reg_hash: RegisterHash,
) -> Self {
Self {
id,
outdated: false,
reg,
reg_hash,
}
}
pub fn pytket_register(&self) -> &PytketRegister {
&self.reg
}
pub fn pytket_register_arc(&self) -> Arc<PytketRegister> {
self.reg.clone()
}
pub fn ty(&self) -> Arc<Type> {
static BOOL_TYPE: LazyLock<Arc<Type>> = LazyLock::new(|| bool_t().into());
BOOL_TYPE.clone()
}
pub(super) fn id(&self) -> TrackedBitId {
self.id
}
pub(super) fn reg_hash(&self) -> RegisterHash {
self.reg_hash
}
pub fn is_outdated(&self) -> bool {
self.outdated
}
pub(super) fn mark_outdated(&mut self) {
self.outdated = true;
}
}
impl PartialEq for TrackedQubit {
fn eq(&self, other: &Self) -> bool {
self.id == other.id && self.outdated == other.outdated && self.reg_hash == other.reg_hash
}
}
impl PartialEq for TrackedBit {
fn eq(&self, other: &Self) -> bool {
self.id == other.id && self.outdated == other.outdated && self.reg_hash == other.reg_hash
}
}
impl std::hash::Hash for TrackedQubit {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
self.outdated.hash(state);
self.reg_hash.hash(state);
}
}
impl std::hash::Hash for TrackedBit {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
self.outdated.hash(state);
self.reg_hash.hash(state);
}
}
#[cfg(test)]
mod tests {
use super::*;
use hugr::extension::prelude::{bool_t, qb_t};
use hugr::types::Type;
use rstest::rstest;
use std::sync::Arc;
use tket_json_rs::register::ElementId;
#[rstest]
fn tracked_qubit_basic_behaviour() {
let reg = Arc::new(ElementId("q".to_string(), vec![0]));
let mut tq = TrackedQubit::new(TrackedQubitId(0), reg.clone());
assert!(!tq.is_outdated());
assert_eq!(tq.pytket_register(), &*reg);
assert_eq!(tq.pytket_register_arc(), reg);
assert_eq!(&*tq.ty(), &Type::from(qb_t()));
tq.mark_outdated();
assert!(tq.is_outdated());
}
#[rstest]
fn tracked_bit_basic_behaviour() {
let reg = Arc::new(ElementId("c".to_string(), vec![1]));
let mut tb = TrackedBit::new(TrackedBitId(0), reg.clone());
assert!(!tb.is_outdated());
assert_eq!(tb.pytket_register(), &*reg);
assert_eq!(tb.pytket_register_arc(), reg);
assert_eq!(&*tb.ty(), &Type::from(bool_t()));
tb.mark_outdated();
assert!(tb.is_outdated());
}
}