netlistdb 0.3.1

Heterogeneous VLSI circuit netlist database with support for vector nets, hierarchical modules, assignments, etc.
Documentation
//! Implementation of a tree-like hierarchical name structure.

use std::fmt;
use std::hash::Hash;
use std::sync::Arc;
use arcstr::Substr;

/// Hierarchical name representation.
#[derive(PartialEq, Eq, Clone)]
pub struct HierName {
    /// Name of the current layer
    pub cur: Substr,
    /// Name of the parent layers.
    pub prev: Option<Arc<HierName>>,
}

/// Reverse iterator of a [`HierName`], yielding cell names
/// from the bottom to the top module.
pub struct HierNameRevIter<'i>(Option<&'i HierName>);

impl<'i> Iterator for HierNameRevIter<'i> {
    type Item = &'i Substr;

    #[inline]
    fn next(&mut self) -> Option<&'i Substr> {
        let name = self.0?;
        if name.cur.len() == 0 {
            return None
        }
        let ret = &name.cur;
        self.0 = name.prev.as_ref().map(|a| a.as_ref());
        Some(ret)
    }
}

impl<'i> IntoIterator for &'i HierName {
    type Item = &'i Substr;
    type IntoIter = HierNameRevIter<'i>;

    #[inline]
    fn into_iter(self) -> HierNameRevIter<'i> {
        HierNameRevIter(Some(self))
    }
}

/// Hashing a HierName.
/// 
/// Our guarantee here is that
/// `Hash(HierName[a/b/c]) :== Hash(c, b, a)`.
/// 
/// This is essential for different HierName implementations
/// to agree with each other on hash values.
/// One can find a tricky example in SPEF parser's HierName.
impl Hash for HierName {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        for s in self.iter() {
            s.hash(state);
        }
    }
}

impl HierName {
    #[inline]
    pub fn single(cur: Substr) -> Self {
        HierName { cur, prev: None }
    }

    #[inline]
    pub fn empty() -> Self {
        HierName { cur: arcstr::literal_substr!(""), prev: None }
    }

    #[inline]
    pub fn is_empty(&self) -> bool {
        self.prev.is_none() && self.cur.len() == 0
    }

    #[inline]
    pub fn iter(&self) -> HierNameRevIter {
        (&self).into_iter()
    }
}

impl fmt::Display for HierName {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(v) = &self.prev {
            write!(f, "{}/", v)?;
        }
        write!(f, "{}", self.cur)
    }
}

impl fmt::Debug for HierName {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "HierName({})", self)
    }
}

#[test]
fn test_hier_name() {
    use arcstr::literal_substr;
    let h1 = Arc::from(HierName{
        cur: literal_substr!("top"),
        prev: None
    });
    let h2 = Arc::from(HierName{
        cur: literal_substr!("mod1"),
        prev: Some(h1.clone())
    });
    let h3 = Arc::from(HierName{
        cur: literal_substr!("leaf1"),
        prev: Some(h2.clone())
    });
    let h3_ = Arc::from(HierName{
        cur: literal_substr!("leaf2"),
        prev: Some(h2.clone())
    });
    assert_eq!(format!("{}", h3), "top/mod1/leaf1");
    assert_eq!(format!("{:?}", h3_), "HierName(top/mod1/leaf2)");
    assert_eq!(h3.iter().map(|a| a.as_ref()).collect::<Vec<&str>>(),
               vec!["leaf1", "mod1", "top"]);
}


/// We use this to unify netlistdb::HierName and other
/// implementations, such as
/// spefparse::HierName, sdfparse::SDFPath, etc.
/// 
/// See a great post on this:
/// <https://stackoverflow.com/questions/45786717/how-to-implement-hashmap-with-two-keys>
pub trait GeneralHierName {
    fn ident_vec(&self) -> Vec<&str>;
}

impl<T, S> GeneralHierName for T
where for<'i> &'i T: IntoIterator<Item = &'i S>,
      T: Hash,
      S: AsRef<str>
{
    #[inline]
    fn ident_vec(&self) -> Vec<&str> {
        self.into_iter().map(|a| a.as_ref()).collect()
    }
}

impl Hash for dyn GeneralHierName + '_ {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        for s in self.ident_vec().iter().rev() {
            s.hash(state);
        }
    }
}

// Below won't work because it trips over the orphan rule.
// See this answer: https://stackoverflow.com/a/63131661/11815215
// 
// impl<T: GeneralHierName> std::borrow::Borrow<dyn GeneralHierName> for T {
//     #[inline]
//     fn borrow(&self) -> &dyn GeneralHierName {
//         self
//     }
// }

impl<'i> std::borrow::Borrow<dyn GeneralHierName + 'i> for HierName {
    #[inline]
    fn borrow(&self) -> &(dyn GeneralHierName + 'i) {
        self
    }
}

impl<'i> std::borrow::Borrow<dyn GeneralHierName + 'i> for &'i HierName {
    #[inline]
    fn borrow(&self) -> &(dyn GeneralHierName + 'i) {
        *self
    }
}

impl PartialEq for dyn GeneralHierName + '_ {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        self.ident_vec() == other.ident_vec()
    }
}

impl Eq for dyn GeneralHierName + '_ {}

/// We use this to unify the hash query of pin names.
/// A pin name consists of (cell hierarchy, pin type, bus id)
pub trait GeneralPinName {
    fn hierarchy(&self) -> &dyn GeneralHierName;
    fn pin_type(&self) -> &str;
    fn bus_id(&self) -> Option<isize>;
}

impl<C, S> GeneralPinName for (C, S, Option<isize>)
where C: GeneralHierName, S: AsRef<str>
{
    #[inline]
    fn hierarchy(&self) -> &dyn GeneralHierName {
        &self.0
    }

    #[inline]
    fn pin_type(&self) -> &str {
        self.1.as_ref()
    }

    #[inline]
    fn bus_id(&self) -> Option<isize> {
        self.2
    }
}

impl Hash for dyn GeneralPinName + '_ {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        // warning: this relies on the tuple hash implementation (https://doc.rust-lang.org/src/core/hash/mod.rs.html) to hash every elements one by one.
        for s in self.hierarchy().ident_vec().iter().rev() {
            s.hash(state);
        }
        self.pin_type().hash(state);
        self.bus_id().hash(state);
    }
}

impl<'i> std::borrow::Borrow<dyn GeneralPinName + 'i>
    for (HierName, Substr, Option<isize>)
{
    #[inline]
    fn borrow(&self) -> &(dyn GeneralPinName + 'i) {
        self
    }
}

impl<'i, 'j> std::borrow::Borrow<dyn GeneralPinName + 'i>
    for &'j (HierName, Substr, Option<isize>)
{
    #[inline]
    fn borrow(&self) -> &(dyn GeneralPinName + 'i) {
        *self
    }
}

impl PartialEq for dyn GeneralPinName + '_ {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        self.bus_id() == other.bus_id() &&
            self.pin_type() == other.pin_type() &&
            self.hierarchy().ident_vec() == other.hierarchy().ident_vec()
    }
}

impl Eq for dyn GeneralPinName + '_ {}

/// this struct is used to zero-copy refer to a general
/// pin tuple, for map lookup.
pub struct RefPinName<'a, 'b, T: GeneralHierName>(
    pub &'a T, pub &'b str, pub Option<isize>
);

impl<'a, 'b, T: GeneralHierName + Hash> Hash for RefPinName<'a, 'b, T> {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.0.hash(state);
        self.1.hash(state);
        self.2.hash(state);
    }
}

impl<'a, 'b, T: GeneralHierName> GeneralPinName for RefPinName<'a, 'b, T> {
    #[inline]
    fn hierarchy(&self) -> &dyn GeneralHierName {
        &*self.0
    }


    #[inline]
    fn pin_type(&self) -> &str {
        self.1.as_ref()
    }

    #[inline]
    fn bus_id(&self) -> Option<isize> {
        self.2
    }
}