diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 58adcfc..85de526 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -4,13 +4,17 @@ mod fmt; pub mod parser; -use crate::{library::AttributeType, ArcStr}; -use core::hash::{BuildHasher as _, Hash, Hasher as _}; -use core::{fmt::Write, num::ParseIntError, str::FromStr}; +use crate::{common::f64_into_hash_ord_fn, library::AttributeType, ArcStr}; +use core::{ + cmp::Ordering, + fmt::Write, + hash::{BuildHasher as _, Hash as _, Hasher as _}, + num::ParseIntError, + str::FromStr, +}; pub use fmt::{CodeFormatter, DefaultCodeFormatter, DefaultIndentation, Indentation}; use itertools::{izip, Itertools as _}; use nom::{error::Error, IResult}; -use ordered_float::NotNan; use std::collections::HashMap; const DEFINED_COMMENT: &str = " /* user defined attribute */"; @@ -83,13 +87,13 @@ pub struct GroupWrapper { } impl Ord for GroupWrapper { #[inline] - fn cmp(&self, other: &Self) -> core::cmp::Ordering { + fn cmp(&self, other: &Self) -> Ordering { self.title.cmp(&other.title) } } impl PartialOrd for GroupWrapper { #[inline] - fn partial_cmp(&self, other: &Self) -> Option { + fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } @@ -135,9 +139,7 @@ impl PartialEq for SimpleDefined { (Self::Float(l0), Self::Float(r0)) => { l0.len() == r0.len() && izip!(l0, r0).all(|lr| match lr { - (Ok(l), Ok(r)) => unsafe { - NotNan::new_unchecked(*l) == NotNan::new_unchecked(*r) - }, + (Ok(l), Ok(r)) => f64_into_hash_ord_fn(l) == f64_into_hash_ord_fn(r), (Err(l), Err(r)) => l == r, _ => false, }) @@ -149,39 +151,37 @@ impl PartialEq for SimpleDefined { impl Eq for SimpleDefined {} impl PartialOrd for SimpleDefined { #[inline] - fn partial_cmp(&self, other: &Self) -> Option { + fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for SimpleDefined { #[inline] - fn cmp(&self, other: &Self) -> std::cmp::Ordering { + fn cmp(&self, other: &Self) -> Ordering { match (self, other) { - (SimpleDefined::Boolean(l), SimpleDefined::Boolean(r)) => l.cmp(r), - (SimpleDefined::String(l), SimpleDefined::String(r)) => l.cmp(r), - (SimpleDefined::Integer(l), SimpleDefined::Integer(r)) => l.cmp(r), - (SimpleDefined::Float(l), SimpleDefined::Float(r)) => match l.len().cmp(&r.len()) { - std::cmp::Ordering::Less => std::cmp::Ordering::Less, - std::cmp::Ordering::Greater => std::cmp::Ordering::Greater, - std::cmp::Ordering::Equal => l + (Self::Boolean(l), Self::Boolean(r)) => l.cmp(r), + (Self::String(l), Self::String(r)) => l.cmp(r), + (Self::Integer(l), Self::Integer(r)) => l.cmp(r), + (Self::Float(l), Self::Float(r)) => match l.len().cmp(&r.len()) { + Ordering::Less => Ordering::Less, + Ordering::Greater => Ordering::Greater, + Ordering::Equal => l .iter() .map(|res| match res { - Ok(f) => Ok(unsafe { NotNan::new_unchecked(*f) }), + Ok(f) => Ok(f64_into_hash_ord_fn(f)), Err(s) => Err(s), }) .cmp(r.iter().map(|res| match res { - Ok(f) => Ok(unsafe { NotNan::new_unchecked(*f) }), + Ok(f) => Ok(f64_into_hash_ord_fn(f)), Err(s) => Err(s), })), }, - (SimpleDefined::Boolean(_), _) => std::cmp::Ordering::Less, - (_, SimpleDefined::Boolean(_)) => std::cmp::Ordering::Greater, - (_, SimpleDefined::Float(_)) => std::cmp::Ordering::Less, - (SimpleDefined::Float(_), _) => std::cmp::Ordering::Greater, - (SimpleDefined::String(_), SimpleDefined::Integer(_)) => std::cmp::Ordering::Less, - (SimpleDefined::Integer(_), SimpleDefined::String(_)) => { - std::cmp::Ordering::Greater - } + (Self::Boolean(_), _) + | (_, Self::Float(_)) + | (Self::String(_), Self::Integer(_)) => Ordering::Less, + (Self::Float(_), _) + | (_, Self::Boolean(_)) + | (Self::Integer(_), Self::String(_)) => Ordering::Greater, } } } diff --git a/src/ast/parser.rs b/src/ast/parser.rs index a93f5c6..57ae84a 100644 --- a/src/ast/parser.rs +++ b/src/ast/parser.rs @@ -363,7 +363,7 @@ pub(crate) fn simple<'a>( } #[inline] pub(crate) fn float_one(i: &str) -> IResult<&str, f64, Error<&str>> { - #[expect(clippy::string_slice, clippy::undocumented_unsafe_blocks)] + #[expect(clippy::string_slice)] match fast_float2::parse_partial(i) { Ok((f, pos)) => Ok((&i[pos..], f)), Err(_) => Err(nom::Err::Error(Error::new(i, ErrorKind::Float))), @@ -388,7 +388,6 @@ fn int_usize(i: &str) -> IResult<&str, usize, Error<&str>> { } #[inline] -#[expect(clippy::type_complexity)] pub(crate) fn complex_id_vector<'a>( i: &'a str, line_num: &mut usize, diff --git a/src/cell/items.rs b/src/cell/items.rs index c6ba3d3..73cf2bc 100644 --- a/src/cell/items.rs +++ b/src/cell/items.rs @@ -3,7 +3,10 @@ use crate::{ join_fmt, CodeFormatter, ComplexAttri, ComplexParseError, GroupComments, GroupFn, GroupSet, Indentation, NamedGroup, ParseScope, SimpleAttri, SimpleParseRes, }, - common::{items::WordSet, table::CompactCcsPower}, + common::{ + items::{NameList, WordSet}, + table::CompactCcsPower, + }, expression::{logic, LogicBooleanExpression, PowerGroundBooleanExpression}, pin::Direction, timing::items::Mode, @@ -46,10 +49,14 @@ pub struct LeakagePower { #[size = 8] #[liberty(simple(type = Option))] pub power_level: Option, - #[id] + #[id( + borrow = "crate::common::items::RefNameList<'_>", + check_fn = "crate::common::items::namelist_borrow", + with_ref = false + )] #[size = 64] #[liberty(simple)] - pub related_pg_pin: WordSet, + pub related_pg_pin: NameList, #[id( borrow = "Option<&LogicBooleanExpression>", check_fn = "mut_set::borrow_option!", @@ -502,14 +509,22 @@ pub struct DynamicCurrent { #[size = 80] #[liberty(simple(type = Option))] pub when: Option, - #[id] + #[id( + borrow = "crate::common::items::RefNameList<'_>", + check_fn = "crate::common::items::namelist_borrow", + with_ref = false + )] #[size = 64] #[liberty(simple)] - pub related_inputs: WordSet, - #[id] + pub related_inputs: NameList, + #[id( + borrow = "crate::common::items::RefNameList<'_>", + check_fn = "crate::common::items::namelist_borrow", + with_ref = false + )] #[size = 64] #[liberty(simple)] - pub related_outputs: WordSet, + pub related_outputs: NameList, #[size = 24] #[liberty(complex(type = Option))] pub typical_capacitances: Option>, diff --git a/src/common/impls.rs b/src/common/impls.rs index dc603d2..7fe44fb 100644 --- a/src/common/impls.rs +++ b/src/common/impls.rs @@ -8,7 +8,10 @@ use crate::{ }, ArcStr, }; -use core::fmt::{self, Write}; +use core::{ + fmt::{self, Write}, + str::FromStr, +}; use itertools::Itertools as _; use super::{ @@ -18,7 +21,6 @@ use super::{ crate::ast::impl_self_builder!(f64); impl SimpleAttri for f64 { #[inline] - #[expect(clippy::undocumented_unsafe_blocks)] fn nom_parse<'a>(i: &'a str, scope: &mut ParseScope) -> ast::SimpleParseRes<'a, Self> { ast::parser::simple_custom(i, &mut scope.line_num, ast::parser::float_one) } @@ -117,8 +119,7 @@ impl NameAttri for ArcStr { impl NameAttri for NameList { #[inline] fn parse(v: Vec<&str>) -> Result { - let l = v.len(); - match l { + match v.len() { 0 => Err(IdError::length_dismatch(1, 0, v)), #[expect(clippy::indexing_slicing)] 1 => Ok(Self::Name(v[0].into())), @@ -133,6 +134,60 @@ impl NameAttri for NameList { write!(f, "{self}") } } +impl FromStr for NameList { + type Err = (); + #[inline] + #[expect(clippy::unwrap_in_result, clippy::unwrap_used)] + fn from_str(s: &str) -> Result { + let mut v: Vec<_> = s + .split(' ') + .filter_map(|_s| if _s.is_empty() { None } else { Some(ArcStr::from(_s)) }) + .collect(); + match v.len() { + 0 => Err(()), + 1 => Ok(Self::Name(v.pop().unwrap())), + _ => Ok(Self::List(WordSet { inner: v.into_iter().map(ArcStr::from).collect() })), + } + } +} +crate::ast::impl_self_builder!(NameList); +impl SimpleAttri for NameList { + #[inline] + fn nom_parse<'a>( + i: &'a str, + scope: &mut ParseScope, + ) -> ast::SimpleParseRes<'a, Self::Builder> { + ast::nom_parse_from_str(i, scope) + } + #[inline] + fn is_set(&self) -> bool { + match self { + NameList::Name(s) => !s.is_empty(), + NameList::List(word_set) => word_set.is_set(), + } + } + #[inline] + fn fmt_self( + &self, + f: &mut CodeFormatter<'_, T, I>, + ) -> fmt::Result { + match self { + Self::Name(s) => { + if is_word(s) { + write!(f, "{s}") + } else { + write!(f, "\"{s}\"") + } + } + Self::List(set) => join_fmt_no_quote( + set.inner.iter().sorted(), + f, + |s, ff| if is_word(s) { write!(ff, "{s}") } else { write!(ff, "\"{s}\"") }, + " ", + ), + } + } +} impl fmt::Display for NameList { #[inline] @@ -263,7 +318,7 @@ impl ast::ParsingBuilder for [f64; N] { builder } } -// FIXME + impl ComplexAttri for [f64; N] { #[inline] fn parse<'a, I: Iterator>( diff --git a/src/common/items.rs b/src/common/items.rs index 4710fad..57346fc 100644 --- a/src/common/items.rs +++ b/src/common/items.rs @@ -187,12 +187,10 @@ impl fmt::Display for WordSet { impl Ord for WordSet { #[inline] fn cmp(&self, other: &Self) -> Ordering { - if self.inner.is_subset(&other.inner) { - Ordering::Less - } else if self.inner.is_superset(&other.inner) { - Ordering::Greater - } else { - Ordering::Equal + match self.inner.len().cmp(&other.inner.len()) { + Ordering::Less => Ordering::Less, + Ordering::Greater => Ordering::Greater, + Ordering::Equal => self.inner.iter().sorted().cmp(other.inner.iter().sorted()), } } } @@ -201,14 +199,14 @@ impl Ord for WordSet { impl PartialOrd for WordSet { #[inline] fn partial_cmp(&self, other: &Self) -> Option { - if self.inner.len() == other.inner.len() { - self.inner.iter().sorted().partial_cmp(other.inner.iter().sorted()) - } else if self.inner.is_subset(&other.inner) { - Some(Ordering::Less) - } else if self.inner.is_superset(&other.inner) { - Some(Ordering::Greater) - } else { - None + match self.inner.len().cmp(&other.inner.len()) { + Ordering::Less => self.inner.is_subset(&other.inner).then_some(Ordering::Less), + Ordering::Greater => { + self.inner.is_superset(&other.inner).then_some(Ordering::Greater) + } + Ordering::Equal => { + self.inner.iter().sorted().partial_cmp(other.inner.iter().sorted()) + } } } } diff --git a/src/common/mod.rs b/src/common/mod.rs index 9d583b6..8da25b4 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -15,6 +15,8 @@ pub(crate) fn parse_f64>(s: S) -> Result fast_float2::parse(s) } #[inline] -pub(crate) fn f64_into_hash_ord_fn(val: &f64) -> NotNan { +#[expect(clippy::trivially_copy_pass_by_ref)] +pub(crate) const fn f64_into_hash_ord_fn(val: &f64) -> NotNan { + // SAFETY: convert float to hash & ord unsafe { NotNan::new_unchecked(*val) } } diff --git a/src/common/table.rs b/src/common/table.rs index 3a0cb91..4679c6d 100644 --- a/src/common/table.rs +++ b/src/common/table.rs @@ -112,7 +112,6 @@ pub struct DriverWaveform { #[derive(serde::Serialize, serde::Deserialize)] #[serde(bound = "C::Table: serde::Serialize + serde::de::DeserializeOwned")] pub struct TableLookUp2D { - // TODO: unit #[size = 8] #[liberty(name)] #[id(borrow = "Option<&str>", check_fn = "mut_set::borrow_option!", with_ref = false)] @@ -277,7 +276,6 @@ impl SimpleAttri for VariableTypeCompactLutTemplateIndex3 { #[derive(serde::Serialize, serde::Deserialize)] #[serde(bound = "C::Table: serde::Serialize + serde::de::DeserializeOwned")] pub struct Vector3D { - // TODO: unit #[size = 8] #[liberty(name)] #[id(borrow = "Option<&str>", check_fn = "mut_set::borrow_option!", with_ref = false)] @@ -315,7 +313,6 @@ pub struct Vector3D { #[derive(serde::Serialize, serde::Deserialize)] #[serde(bound = "C::Table: serde::Serialize + serde::de::DeserializeOwned")] pub struct ReferenceTimeVector3D { - // TODO: unit #[size = 8] #[liberty(name)] #[id(borrow = "Option<&str>", check_fn = "mut_set::borrow_option!", with_ref = false)] @@ -357,7 +354,6 @@ pub struct ReferenceTimeVector3D { #[derive(serde::Serialize, serde::Deserialize)] #[serde(bound = "C::Table: serde::Serialize + serde::de::DeserializeOwned")] pub struct Vector4D { - // TODO: unit #[size = 8] #[liberty(name)] #[id(borrow = "Option<&str>", check_fn = "mut_set::borrow_option!", with_ref = false)] @@ -443,7 +439,6 @@ pub struct Vector4D { #[derive(serde::Serialize, serde::Deserialize)] #[serde(bound = "C::Table: serde::Serialize + serde::de::DeserializeOwned")] pub struct CompactCcsPower { - // TODO: unit #[size = 8] #[liberty(name)] #[id(borrow = "Option<&str>", check_fn = "mut_set::borrow_option!", with_ref = false)] @@ -701,7 +696,6 @@ impl GroupFn for CompactCcsPower {} #[derive(serde::Serialize, serde::Deserialize)] #[serde(bound = "C::Table: serde::Serialize + serde::de::DeserializeOwned")] pub struct TableLookUp3D { - // TODO: unit #[size = 8] #[liberty(name)] #[id(borrow = "Option<&str>", check_fn = "mut_set::borrow_option!", with_ref = false)] @@ -737,7 +731,7 @@ pub struct TableLookUp3D { #[derive(serde::Serialize, serde::Deserialize)] #[serde(bound = "C::Table: serde::Serialize + serde::de::DeserializeOwned")] pub struct TableLookUp1D { - // // TODO: unit + // // unit: (), #[size = 8] #[liberty(name)] @@ -774,7 +768,7 @@ impl GroupFn for TableLookUp1D {} #[derive(serde::Serialize, serde::Deserialize)] #[serde(bound = "C::Table: serde::Serialize + serde::de::DeserializeOwned")] pub struct CompactCcsTable { - // // TODO: unit + // // unit: (), #[size = 8] #[liberty(name)] diff --git a/src/internal_power/mod.rs b/src/internal_power/mod.rs index 85784c8..a15cb72 100644 --- a/src/internal_power/mod.rs +++ b/src/internal_power/mod.rs @@ -1,7 +1,7 @@ use crate::{ ast::{Attributes, GroupComments, GroupFn}, common::{ - items::{Domain, WordSet}, + items::{Domain, NameList}, table::TableLookUp, }, expression::LogicBooleanExpression, @@ -30,14 +30,22 @@ pub struct InternalPower { // equal_or_opposite_output // falling_together_group // power_level - #[id] + #[id( + borrow = "crate::common::items::RefNameList<'_>", + check_fn = "crate::common::items::namelist_borrow", + with_ref = false + )] #[size = 64] #[liberty(simple)] - pub related_pin: WordSet, - #[id] + pub related_pin: NameList, + #[id( + borrow = "crate::common::items::RefNameList<'_>", + check_fn = "crate::common::items::namelist_borrow", + with_ref = false + )] #[size = 64] #[liberty(simple)] - pub related_pg_pin: WordSet, + pub related_pg_pin: NameList, // rising_together_group // switching_interval // switching_together_group diff --git a/src/pin/bundle.rs b/src/pin/bundle.rs index 5b03f15..c968272 100644 --- a/src/pin/bundle.rs +++ b/src/pin/bundle.rs @@ -16,7 +16,11 @@ use crate::{ #[serde(bound = "C::Pin: serde::Serialize + serde::de::DeserializeOwned")] pub struct Bundle { /// Name of the pin - #[id] + #[id( + borrow = "crate::common::items::RefNameList<'_>", + check_fn = "crate::common::items::namelist_borrow", + with_ref = false + )] #[size = 48] #[liberty(name)] pub name: NameList, diff --git a/src/pin/mod.rs b/src/pin/mod.rs index 98a0c31..6588e41 100644 --- a/src/pin/mod.rs +++ b/src/pin/mod.rs @@ -5,7 +5,7 @@ use crate::{ ast::{Attributes, GroupComments, GroupFn, GroupSet}, ccsn::{CCSNStage, ReceiverCapacitance}, common::items::{NameList, WordSet}, - expression::{logic, BooleanExpression}, + expression::{logic, BooleanExpression, PowerGroundBooleanExpression}, internal_power::InternalPower, timing::Timing, ArcStr, Ctx, @@ -141,10 +141,9 @@ pub struct Pin { #[size = 1] #[liberty(simple(type = Option))] pub alive_during_partial_power_down: Option, - // TODO #[size = 32] #[liberty(simple(type = Option))] - pub power_down_function: Option, + pub power_down_function: Option, /// Reference-Instance - #[id] + #[id( + borrow = "crate::common::items::RefNameList<'_>", + check_fn = "crate::common::items::namelist_borrow", + with_ref = false + )] #[size = 64] #[liberty(simple)] - pub related_pin: WordSet, + pub related_pin: NameList, /// The `rise_resistance` attribute represents the load-dependent output resistance, /// or drive capability, for a logic 0-to-1 transition. /// diff --git a/src/units.rs b/src/units.rs index 18c0b8a..0ad0330 100644 --- a/src/units.rs +++ b/src/units.rs @@ -247,7 +247,7 @@ pub struct CapacitiveLoadUnit { impl CapacitiveLoadUnit { #[inline] #[must_use] - #[expect(clippy::arithmetic_side_effects, clippy::float_arithmetic)] + #[expect(clippy::float_arithmetic)] pub fn value(&self) -> f64 { if self.ff_pf { self.val * 1e-15