#![allow(missing_docs)]
use crate::traits::{HierarchyBase, HierarchyEdit};
use std::hash::{Hash, Hasher};
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
pub struct RwRefAccess<T> {
base: Arc<RwLock<T>>,
}
impl<T> RwRefAccess<T> {
pub fn new(base: T) -> Self {
Self {
base: Arc::new(RwLock::new(base)),
}
}
pub fn read(&self) -> RwLockReadGuard<'_, T> {
self.base.read().expect("Failed to get read access.")
}
pub fn write(&self) -> RwLockWriteGuard<'_, T> {
self.base.write().expect("Failed to get write access.")
}
}
impl<T> Clone for RwRefAccess<T> {
fn clone(&self) -> Self {
Self {
base: self.base.clone(),
}
}
}
impl<T> Eq for RwRefAccess<T> {}
impl<T> PartialEq for RwRefAccess<T> {
fn eq(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.base, &other.base)
}
}
impl<T> Hash for RwRefAccess<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
Arc::as_ptr(&self.base).hash(state)
}
}
impl<H: HierarchyBase> RwRefAccess<H> {
fn cell(&self, id: H::CellId) -> CellRef<H> {
CellRef {
base: self.clone(),
id,
}
}
fn cell_inst(&self, id: H::CellInstId) -> CellInstRef<H> {
CellInstRef {
base: self.clone(),
id,
}
}
pub fn each_cell(&self) -> Vec<CellRef<H>> {
self.read().each_cell().map(|id| self.cell(id)).collect()
}
pub fn num_cells(&self) -> usize {
self.read().num_cells()
}
pub fn cell_by_name(&self, name: &str) -> Option<CellRef<H>> {
self.read().cell_by_name(name).map(|id| self.cell(id))
}
}
impl<H: HierarchyEdit> RwRefAccess<H> {
pub fn create_cell(&self, name: H::NameType) -> CellRef<H> {
let id = self.write().create_cell(name);
self.cell(id)
}
pub fn remove_cell(&self, cell: CellRef<H>) {
self.write().remove_cell(&cell.id)
}
}
#[derive(Clone)]
pub struct CellRef<H: HierarchyBase> {
pub(super) base: RwRefAccess<H>,
pub(super) id: H::CellId,
}
impl<T: HierarchyBase> Eq for CellRef<T> {}
impl<T: HierarchyBase> PartialEq for CellRef<T> {
fn eq(&self, other: &Self) -> bool {
self.base == other.base && self.id == other.id
}
}
impl<T: HierarchyBase> Hash for CellRef<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.base.hash(state);
self.id.hash(state);
}
}
impl<H: HierarchyBase> CellRef<H> {
pub fn base(&self) -> &RwRefAccess<H> {
&self.base
}
pub fn id(&self) -> H::CellId {
self.id.clone()
}
pub fn name(&self) -> H::NameType {
self.base.read().cell_name(&self.id)
}
pub fn each_cell_instance_id(&self) -> Vec<H::CellInstId> {
self.base.read().each_cell_instance_vec(&self.id)
}
pub fn each_cell_instance(&self) -> Vec<CellInstRef<H>> {
self.base
.read()
.each_cell_instance(&self.id)
.map(move |id| CellInstRef {
base: self.base.clone(),
id,
})
.collect()
}
pub fn cell_instance_by_name(&self, name: &str) -> Option<CellInstRef<H>> {
self.base
.read()
.cell_instance_by_name(&self.id, name)
.map(|id| CellInstRef {
base: self.base.clone(),
id,
})
}
pub fn each_reference_id(&self) -> Vec<H::CellInstId> {
self.base.read().each_cell_reference_vec(&self.id)
}
pub fn each_reference(&self) -> Vec<CellInstRef<H>> {
self.base
.read()
.each_cell_reference(&self.id)
.map(|id| CellInstRef {
base: self.base.clone(),
id,
})
.collect()
}
pub fn each_cell_dependency(&self) -> Vec<CellRef<H>> {
self.base
.read()
.each_cell_dependency(&self.id)
.map(|id| CellRef {
base: self.base.clone(),
id,
})
.collect()
}
pub fn each_dependent_cell(&self) -> Vec<CellRef<H>> {
self.base
.read()
.each_dependent_cell(&self.id)
.map(|id| CellRef {
base: self.base.clone(),
id,
})
.collect()
}
pub fn num_child_instances(&self) -> usize {
self.base.read().num_child_instances(&self.id)
}
}
impl<H: HierarchyEdit> CellRef<H> {
pub fn create_instance(
&self,
template: &CellRef<H>,
name: Option<H::NameType>,
) -> CellInstRef<H> {
let id = self
.base
.write()
.create_cell_instance(&self.id, &template.id, name);
self.base.cell_inst(id)
}
pub fn remove_instance(&self, inst: CellInstRef<H>) {
self.base.write().remove_cell_instance(&inst.id);
}
}
#[derive(Clone, Hash)]
pub struct CellInstRef<H: HierarchyBase> {
pub(super) base: RwRefAccess<H>,
pub(super) id: H::CellInstId,
}
impl<T: HierarchyBase> Eq for CellInstRef<T> {}
impl<T: HierarchyBase> PartialEq for CellInstRef<T> {
fn eq(&self, other: &Self) -> bool {
self.base == other.base && self.id == other.id
}
}
impl<H: HierarchyBase> CellInstRef<H> {
pub fn base(&self) -> &RwRefAccess<H> {
&self.base
}
pub fn id(&self) -> H::CellInstId {
self.id.clone()
}
pub fn name(&self) -> Option<H::NameType> {
self.base.read().cell_instance_name(&self.id)
}
pub fn parent(&self) -> CellRef<H> {
CellRef {
base: self.base.clone(),
id: self.parent_id(),
}
}
pub fn template(&self) -> CellRef<H> {
CellRef {
base: self.base.clone(),
id: self.template_id(),
}
}
pub fn parent_id(&self) -> H::CellId {
self.base.read().parent_cell(&self.id)
}
pub fn template_id(&self) -> H::CellId {
self.base.read().template_cell(&self.id)
}
}
#[cfg(test)]
mod tests {
use crate::chip::Chip;
use crate::prelude::*;
use crate::rw_reference_access::RwRefAccess;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
fn create_test_chip() -> RwRefAccess<Chip> {
let mut chip = Chip::new();
let top = chip.create_cell("TOP".into());
let sub = chip.create_cell("SUB".into());
let _inst1 = chip.create_cell_instance(&top, &sub, Some("inst1".into()));
RwRefAccess::new(chip)
}
#[test]
fn create_rw_refaccess_from_mutable_reference() {
let mut chip = Chip::new();
let _rw_chip = RwRefAccess::new(&mut chip);
}
fn hash<T: Hash>(t: &T) -> u64 {
let mut s = DefaultHasher::new();
t.hash(&mut s);
s.finish()
}
#[test]
fn test_find_cell_by_name() {
let chip = create_test_chip();
let _top = chip.cell_by_name("TOP").unwrap();
let _sub = chip.cell_by_name("SUB").unwrap();
}
#[test]
fn test_find_cell_instance_by_name() {
let chip = create_test_chip();
let top = chip.cell_by_name("TOP").unwrap();
let _inst1 = top.cell_instance_by_name("inst1").unwrap();
}
#[test]
fn test_cell_equality() {
let chip = create_test_chip();
let top = chip.cell_by_name("TOP").unwrap();
let sub = chip.cell_by_name("SUB").unwrap();
assert!(top == top.clone());
assert!(top != sub);
}
#[test]
fn test_cell_hash() {
let chip = create_test_chip();
let top = chip.cell_by_name("TOP").unwrap();
let sub = chip.cell_by_name("SUB").unwrap();
assert_eq!(hash(&top), hash(&top.clone()));
assert_eq!(hash(&sub), hash(&sub.clone()));
assert_ne!(hash(&top), hash(&sub)); }
#[test]
fn test_cell_instance_equality() {
let chip = create_test_chip();
let top = chip.cell_by_name("TOP").unwrap();
let sub = chip.cell_by_name("SUB").unwrap();
let inst1 = top.cell_instance_by_name("inst1").unwrap();
let inst2 = top.create_instance(&sub, Some("inst2".into()));
assert!(inst1 == inst1.clone());
assert!(inst1 != inst2);
}
#[test]
fn test_create_cell() {
let chip = create_test_chip();
chip.create_cell("NEW".into());
chip.cell_by_name("NEW").unwrap();
}
#[test]
fn test_create_instance() {
let chip = create_test_chip();
let top = chip.cell_by_name("TOP").unwrap();
let sub = chip.cell_by_name("SUB").unwrap();
let inst = top.create_instance(&sub, Some("inst2".into()));
assert!(inst.template() == sub);
assert!(inst.parent() == top);
}
#[test]
fn test_access_child_instances() {
let chip = create_test_chip();
let top = chip.cell_by_name("TOP").unwrap();
let children = top.each_cell_instance();
assert_eq!(children.len(), 1);
}
#[test]
fn test_cell_dependencies() {
let chip = create_test_chip();
let top = chip.cell_by_name("TOP").unwrap();
let sub = chip.cell_by_name("SUB").unwrap();
assert_eq!(top.each_cell_dependency().len(), 1);
assert_eq!(sub.each_cell_dependency().len(), 0);
}
#[test]
fn test_dependent_cells() {
let chip = create_test_chip();
let top = chip.cell_by_name("TOP").unwrap();
let sub = chip.cell_by_name("SUB").unwrap();
assert_eq!(top.each_dependent_cell().len(), 0);
assert_eq!(sub.each_dependent_cell().len(), 1);
}
}