use crate::{
ast::{
join_fmt, CodeFormatter, ComplexAttri, ComplexParseError, GroupComments, GroupFn,
GroupSet, Indentation, NamedGroup, ParseScope, SimpleAttri, SimpleParseRes,
},
common::{items::WordSet, table::CompactCcsPower},
expression::{logic, IdBooleanExpression},
pin::Direction,
timing::items::Mode,
ArcStr, NotNan,
};
use core::{
fmt::{self, Write},
hash::Hash,
str::FromStr,
};
#[mut_set::derive::item(sort)]
#[derive(Debug, Clone)]
#[derive(liberty_macros::Group)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct LeakagePower {
#[id(borrow = "&[ArcStr]")]
#[size = 24]
#[liberty(name)]
pub name: Vec<ArcStr>,
#[size = 32]
#[liberty(comments)]
comments: GroupComments,
#[size = 40]
#[liberty(attributes)]
pub attributes: crate::ast::Attributes,
#[id(borrow = "Option<&str>", check_fn = "mut_set::borrow_option!")]
#[size = 8]
#[liberty(simple(type = Option))]
power_level: Option<ArcStr>,
#[id]
#[size = 64]
#[liberty(simple)]
related_pg_pin: WordSet,
#[id(borrow = "Option<&IdBooleanExpression>", check_fn = "mut_set::borrow_option!")]
#[size = 80]
#[liberty(simple(type = Option))]
when: Option<IdBooleanExpression>,
#[size = 8]
#[liberty(simple)]
value: NotNan<f64>,
#[size = 16]
#[liberty(complex(type = Option))]
mode: Option<Mode>,
}
impl GroupFn for LeakagePower {}
#[cfg(test)]
mod test_sort {
use super::*;
#[test]
fn test_leakage_sort() {
let cell = crate::ast::test_parse::<crate::Cell>(
r#"(CELL) {
leakage_power () {
related_pg_pin : VDD;
value : 1;
}
leakage_power () {
related_pg_pin : VDD;
when : "A*B*Y";
value : 2;
}
leakage_power () {
related_pg_pin : VDD;
when : "!A*B*!Y";
value : 3;
}
leakage_power () {
related_pg_pin : VDD;
when : "A*!B*!Y";
value : 4;
}
leakage_power () {
related_pg_pin : VDD;
when : "!A*!B*!Y";
value : 5;
}
leakage_power () {
related_pg_pin : VSS;
value : 6;
}
leakage_power () {
related_pg_pin : VSS;
when : "A*B*Y";
value : 7;
}
leakage_power () {
related_pg_pin : VSS;
when : "!A*B*!Y";
value : 8;
}
leakage_power () {
related_pg_pin : VSS;
when : "A*!B*!Y";
value : 9;
}
leakage_power () {
related_pg_pin : VSS;
when : "!A*!B*!Y";
value : 10;
}
}
"#,
);
assert_eq!(
vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
cell
.leakage_power
.iter_sort()
.map(|leakage| leakage.value.into_inner() as i8)
.collect::<Vec<_>>()
);
}
}
#[mut_set::derive::item(sort)]
#[derive(Debug, Clone)]
#[derive(liberty_macros::Group)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct Statetable {
#[id(borrow = "&[ArcStr]")]
#[size = 24]
#[liberty(name)]
pub input_nodes: Vec<ArcStr>,
#[id(borrow = "&[ArcStr]")]
#[size = 24]
#[liberty(name)]
pub internal_nodes: Vec<ArcStr>,
#[size = 32]
#[liberty(comments)]
comments: GroupComments,
#[size = 40]
#[liberty(attributes)]
pub attributes: crate::ast::Attributes,
#[size = 24]
#[liberty(simple)]
pub table: Table,
}
impl GroupFn for Statetable {}
impl NamedGroup for Statetable {
#[inline]
fn parse_set_name(&mut self, mut v: Vec<&str>) -> Result<(), crate::ast::IdError> {
let l = v.len();
if l == 2 {
v.pop()
.map_or(Err(crate::ast::IdError::Other("Unkown pop error".into())), |var2| {
v.pop().map_or(
Err(crate::ast::IdError::Other("Unkown pop error".into())),
|var1| {
self.input_nodes =
var1.split_ascii_whitespace().map(ArcStr::from).collect();
self.internal_nodes =
var2.split_ascii_whitespace().map(ArcStr::from).collect();
Ok(())
},
)
})
} else {
Err(crate::ast::IdError::length_dismatch(2, l, v))
}
}
#[inline]
#[expect(clippy::indexing_slicing)]
fn fmt_name<T: Write, I: Indentation>(
&self,
f: &mut CodeFormatter<'_, T, I>,
) -> fmt::Result {
if self.input_nodes.len() == 1 {
write!(f, "{}", self.input_nodes[0])?;
} else {
join_fmt(self.input_nodes.iter(), f, |s, ff| write!(ff, "{s}"), " ")?;
}
write!(f, ", ")?;
if self.internal_nodes.len() == 1 {
write!(f, "{}", self.internal_nodes[0])
} else {
join_fmt(self.internal_nodes.iter(), f, |s, ff| write!(ff, "{s}"), " ")
}
}
}
#[derive(Default, Debug, Clone)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct Table {
pub v: Vec<ArcStr>,
}
impl fmt::Display for Table {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.v, f)
}
}
impl FromStr for Table {
type Err = fmt::Error;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self {
v: s
.split("\\\n")
.filter_map(|line| {
let _l = line
.trim_start()
.trim_end_matches(|c: char| c == ',' || c.is_ascii_whitespace());
if _l.is_empty() {
None
} else {
Some(ArcStr::from(_l))
}
})
.collect(),
})
}
}
impl SimpleAttri for Table {
#[inline]
fn is_set(&self) -> bool {
!self.v.is_empty()
}
#[inline]
fn nom_parse<'a>(i: &'a str, scope: &mut ParseScope) -> SimpleParseRes<'a, Self> {
let (input, simple_multi) = crate::ast::parser::simple_multi(i, &mut scope.line_num)?;
simple_multi
.parse()
.map_or(Ok((input, Err(ArcStr::from(simple_multi)))), |s| Ok((input, Ok(s))))
}
#[inline]
fn fmt_self<T: Write, I: Indentation>(
&self,
f: &mut CodeFormatter<'_, T, I>,
) -> fmt::Result {
let indent = f.indentation();
join_fmt(
self.v.iter(),
f,
|i, ff| write!(ff, "{i}"),
format!(" ,\\\n{indent} ").as_str(),
)
}
}
#[cfg(test)]
mod test_statetable {
use super::*;
#[test]
fn statetable_test() {
_ = crate::ast::test_parse_fmt::<Statetable>(
r#"(" CLK EN SE",ENL) {
table : " H L L : - : L ,\
H L H : - : H ,\
H H L : - : H ,\
H H H : - : H ,\
L - - : - : N ";
}
"#,
r#"
liberty_db::cell::items::Statetable ("CLK EN SE", ENL) {
| table : "H L L : - : L ,\
| H L H : - : H ,\
| H H L : - : H ,\
| H H H : - : H ,\
| L - - : - : N";
}"#,
);
}
}
#[mut_set::derive::item(sort)]
#[derive(Debug, Clone)]
#[derive(liberty_macros::Group)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct PgPin {
#[size = 8]
#[liberty(name)]
#[id(borrow = "Option<&str>", check_fn = "mut_set::borrow_option!")]
name: Option<ArcStr>,
#[size = 32]
#[liberty(comments)]
comments: GroupComments,
#[size = 40]
#[liberty(attributes)]
pub attributes: crate::ast::Attributes,
#[size = 1]
#[liberty(simple(type = Option))]
pub direction: Option<Direction>,
#[size = 8]
#[liberty(simple)]
pub voltage_name: ArcStr,
#[size = 1]
#[liberty(simple)]
pub pg_type: PgType,
#[size = 8]
#[liberty(simple)]
pub user_pg_type: ArcStr,
#[size = 8]
#[liberty(simple)]
pub physical_connection: ArcStr,
#[size = 8]
#[liberty(simple)]
pub related_bias_pin: ArcStr,
#[size = 1]
#[liberty(simple(type = Option))]
pub std_cell_main_rail: Option<bool>,
#[size = 80]
#[liberty(simple(type = Option))]
pub pg_function: Option<IdBooleanExpression>,
#[size = 80]
#[liberty(simple(type = Option))]
pub switch_function: Option<IdBooleanExpression>,
}
impl GroupFn for PgPin {}
#[mut_set::derive::item(sort)]
#[derive(Debug, Clone)]
#[derive(liberty_macros::Group)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct DynamicCurrent {
#[size = 8]
#[liberty(name)]
#[id(borrow = "Option<&str>", check_fn = "mut_set::borrow_option!")]
name: Option<ArcStr>,
#[size = 32]
#[liberty(comments)]
comments: GroupComments,
#[size = 40]
#[liberty(attributes)]
pub attributes: crate::ast::Attributes,
#[id]
#[size = 80]
#[liberty(simple(type = Option))]
pub when: Option<IdBooleanExpression>,
#[id]
#[size = 64]
#[liberty(simple)]
pub related_inputs: WordSet,
#[id]
#[size = 64]
#[liberty(simple)]
pub related_outputs: WordSet,
#[size = 24]
#[liberty(complex(type = Option))]
pub typical_capacitances: Option<Vec<NotNan<f64>>>,
#[size = 64]
#[liberty(group(type = Set))]
#[serde(serialize_with = "GroupSet::<SwitchingGroup>::serialize_with")]
#[serde(deserialize_with = "GroupSet::<SwitchingGroup>::deserialize_with")]
pub switching_group: GroupSet<SwitchingGroup>,
}
impl GroupFn for DynamicCurrent {}
#[mut_set::derive::item(sort)]
#[derive(Debug, Clone)]
#[derive(liberty_macros::Group)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct SwitchingGroup {
#[size = 8]
#[liberty(name)]
#[id(borrow = "Option<&str>", check_fn = "mut_set::borrow_option!")]
name: Option<ArcStr>,
#[size = 32]
#[liberty(comments)]
comments: GroupComments,
#[size = 40]
#[liberty(attributes)]
pub attributes: crate::ast::Attributes,
#[id]
#[size = 1]
#[liberty(complex(type = Option))]
pub input_switching_condition: Option<logic::Edge>,
#[id]
#[size = 1]
#[liberty(complex(type = Option))]
pub output_switching_condition: Option<logic::Edge>,
#[size = 16]
#[liberty(simple(type = Option))]
pub min_input_switching_count: Option<usize>,
#[size = 16]
#[liberty(simple(type = Option))]
pub max_input_switching_count: Option<usize>,
#[size = 64]
#[liberty(group(type = Set))]
#[serde(serialize_with = "GroupSet::<PgCurrent>::serialize_with")]
#[serde(deserialize_with = "GroupSet::<PgCurrent>::deserialize_with")]
pub pg_current: GroupSet<PgCurrent>,
}
impl GroupFn for SwitchingGroup {}
#[mut_set::derive::item(sort)]
#[derive(Debug, Clone)]
#[derive(liberty_macros::Group)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct PgCurrent {
#[size = 8]
#[liberty(name)]
#[id(borrow = "Option<&str>", check_fn = "mut_set::borrow_option!")]
name: Option<ArcStr>,
#[size = 32]
#[liberty(comments)]
comments: GroupComments,
#[size = 40]
#[liberty(attributes)]
pub attributes: crate::ast::Attributes,
#[size = 64]
#[liberty(group(type = Set))]
#[serde(serialize_with = "GroupSet::<CompactCcsPower>::serialize_with")]
#[serde(deserialize_with = "GroupSet::<CompactCcsPower>::deserialize_with")]
pub compact_ccs_power: GroupSet<CompactCcsPower>,
}
impl GroupFn for PgCurrent {}
#[mut_set::derive::item(sort)]
#[derive(Debug, Clone)]
#[derive(liberty_macros::Group)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct IntrinsicParasitic {
#[size = 8]
#[liberty(name)]
name: Option<ArcStr>,
#[size = 32]
#[liberty(comments)]
comments: GroupComments,
#[size = 40]
#[liberty(attributes)]
pub attributes: crate::ast::Attributes,
#[id]
#[liberty(simple(type = Option))]
pub when: Option<IdBooleanExpression>,
#[id]
#[liberty(simple(type = Option))]
pub reference_pg_pin: Option<ArcStr>,
#[liberty(complex(type = Option))]
pub mode: Option<[ArcStr; 2]>,
#[size = 64]
#[liberty(group(type = Set))]
#[serde(serialize_with = "GroupSet::<IntrinsicCapacitance>::serialize_with")]
#[serde(deserialize_with = "GroupSet::<IntrinsicCapacitance>::deserialize_with")]
pub intrinsic_capacitance: GroupSet<IntrinsicCapacitance>,
#[size = 64]
#[liberty(group(type = Set))]
#[serde(serialize_with = "GroupSet::<IntrinsicResistance>::serialize_with")]
#[serde(deserialize_with = "GroupSet::<IntrinsicResistance>::deserialize_with")]
pub intrinsic_resistance: GroupSet<IntrinsicResistance>,
#[size = 64]
#[liberty(group(type = Set))]
#[serde(serialize_with = "GroupSet::<PgPinWithValue>::serialize_with")]
#[serde(deserialize_with = "GroupSet::<PgPinWithValue>::deserialize_with")]
pub total_capacitance: GroupSet<PgPinWithValue>,
}
impl GroupFn for IntrinsicParasitic {}
#[mut_set::derive::item(sort)]
#[derive(Debug, Clone)]
#[derive(liberty_macros::Group)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct IntrinsicCapacitance {
#[size = 8]
#[liberty(name)]
name: Option<ArcStr>,
#[size = 32]
#[liberty(comments)]
comments: GroupComments,
#[size = 40]
#[liberty(attributes)]
pub attributes: crate::ast::Attributes,
#[id]
#[liberty(simple)]
pub value: NotNan<f64>,
#[id]
#[liberty(simple(type = Option))]
pub reference_pg_pin: Option<ArcStr>,
#[size = 128]
#[liberty(group(type = Option))]
pub lut_values: Option<LutValues>,
}
impl GroupFn for IntrinsicCapacitance {}
#[mut_set::derive::item(sort)]
#[derive(Debug, Clone)]
#[derive(liberty_macros::Group)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct IntrinsicResistance {
#[size = 8]
#[liberty(name)]
name: Option<ArcStr>,
#[size = 32]
#[liberty(comments)]
comments: GroupComments,
#[size = 40]
#[liberty(attributes)]
pub attributes: crate::ast::Attributes,
#[liberty(simple)]
#[default = "unsafe{ NotNan::new_unchecked(f64::INFINITY) }"]
pub value: NotNan<f64>,
#[id]
#[liberty(simple(type = Option))]
pub related_output: Option<ArcStr>,
#[id]
#[liberty(simple(type = Option))]
pub reference_pg_pin: Option<ArcStr>,
#[size = 128]
#[liberty(group(type = Option))]
pub lut_values: Option<LutValues>,
}
impl GroupFn for IntrinsicResistance {}
#[mut_set::derive::item(sort)]
#[derive(Debug, Clone)]
#[derive(liberty_macros::Group)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct PgPinWithValue {
#[id]
#[size = 8]
#[liberty(name)]
pg_pin_name: Option<ArcStr>,
#[size = 32]
#[liberty(comments)]
comments: GroupComments,
#[size = 40]
#[liberty(attributes)]
pub attributes: crate::ast::Attributes,
#[size = 8]
#[liberty(simple)]
pub value: NotNan<f64>,
}
impl GroupFn for PgPinWithValue {}
#[mut_set::derive::item(sort)]
#[derive(Debug, Clone)]
#[derive(liberty_macros::Group)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct GateLeakage {
#[id]
#[size = 8]
#[liberty(name)]
input_pin_name: Option<ArcStr>,
#[size = 32]
#[liberty(comments)]
comments: GroupComments,
#[size = 40]
#[liberty(attributes)]
pub attributes: crate::ast::Attributes,
#[size = 16]
#[liberty(simple(type = Option))]
pub input_low_value: Option<NotNan<f64>>,
#[size = 16]
#[liberty(simple(type = Option))]
pub input_high_value: Option<NotNan<f64>>,
}
impl GroupFn for GateLeakage {}
#[mut_set::derive::item(sort)]
#[derive(Debug, Clone)]
#[derive(liberty_macros::Group)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct LeakageCurrent {
#[size = 8]
#[liberty(name)]
name: Option<ArcStr>,
#[size = 32]
#[liberty(comments)]
comments: GroupComments,
#[size = 40]
#[liberty(attributes)]
pub attributes: crate::ast::Attributes,
#[id]
#[size = 80]
#[liberty(simple(type = Option))]
pub when: Option<IdBooleanExpression>,
#[size = 16]
#[liberty(simple(type = Option))]
pub value: Option<NotNan<f64>>,
#[liberty(complex(type = Option))]
pub mode: Option<[ArcStr; 2]>,
#[size = 64]
#[liberty(group(type = Set))]
#[serde(serialize_with = "GroupSet::<PgPinWithValue>::serialize_with")]
#[serde(deserialize_with = "GroupSet::<PgPinWithValue>::deserialize_with")]
pub pg_current: GroupSet<PgPinWithValue>,
#[size = 64]
#[liberty(group(type = Set))]
#[serde(serialize_with = "GroupSet::<GateLeakage>::serialize_with")]
#[serde(deserialize_with = "GroupSet::<GateLeakage>::deserialize_with")]
pub gate_leakage: GroupSet<GateLeakage>,
}
impl GroupFn for LeakageCurrent {}
#[derive(Debug, Clone)]
#[derive(liberty_macros::Group)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct LutValues {
#[liberty(name)]
name: Option<ArcStr>,
#[liberty(comments)]
comments: GroupComments,
#[liberty(attributes)]
pub attributes: crate::ast::Attributes,
#[liberty(complex)]
pub index_1: Vec<NotNan<f64>>,
#[liberty(complex)]
pub values: Vec<NotNan<f64>>,
}
impl GroupFn for LutValues {}
#[derive(Debug, Clone, Copy)]
#[derive(Hash, PartialEq, Eq)]
#[derive(Ord, PartialOrd, Default)]
#[derive(strum_macros::EnumString, strum_macros::EnumIter, strum_macros::Display)]
#[derive(serde::Serialize, serde::Deserialize)]
pub enum PgType {
#[strum(serialize = "primary_power")]
PrimaryPower,
#[strum(serialize = "primary_ground")]
PrimaryGround,
#[strum(serialize = "backup_power")]
BackupPower,
#[strum(serialize = "backup_ground")]
#[default]
BackupGround,
#[strum(serialize = "internal_power")]
InternalPower,
#[strum(serialize = "internal_ground")]
InternalGround,
#[strum(serialize = "pwell")]
Pwell,
#[strum(serialize = "nwell")]
Nwell,
#[strum(serialize = "deepnwell")]
DeepNwell,
#[strum(serialize = "deeppwell")]
DeepPwell,
}
impl SimpleAttri for PgType {
#[inline]
fn nom_parse<'a>(i: &'a str, scope: &mut ParseScope) -> SimpleParseRes<'a, Self> {
crate::ast::nom_parse_from_str(i, scope)
}
}
#[derive(Debug, Clone, Copy)]
#[derive(Hash, PartialEq, Eq)]
#[derive(Ord, PartialOrd)]
#[derive(strum_macros::EnumString, strum_macros::EnumIter, strum_macros::Display)]
#[derive(serde::Serialize, serde::Deserialize)]
pub enum SwitchCellType {
#[strum(serialize = "coarse_grain")]
CoarseGrain,
#[strum(serialize = "fine_grain")]
FineGrain,
}
impl SimpleAttri for SwitchCellType {
#[inline]
fn nom_parse<'a>(i: &'a str, scope: &mut ParseScope) -> SimpleParseRes<'a, Self> {
crate::ast::nom_parse_from_str(i, scope)
}
}
#[derive(Debug, Clone, Copy)]
#[derive(Hash, PartialEq, Eq)]
#[derive(Ord, PartialOrd)]
#[derive(strum_macros::EnumString, strum_macros::EnumIter, strum_macros::Display)]
#[derive(serde::Serialize, serde::Deserialize)]
pub enum FpgaCellType {
#[strum(serialize = "rising_edge_clock_cell")]
RisingEdgeClockCell,
#[strum(serialize = "falling_edge_clock_cell")]
FallingEdgeClockCell,
}
impl SimpleAttri for FpgaCellType {
#[inline]
fn nom_parse<'a>(i: &'a str, scope: &mut ParseScope) -> SimpleParseRes<'a, Self> {
crate::ast::nom_parse_from_str(i, scope)
}
}
#[expect(non_camel_case_types)]
#[derive(Debug, Clone, Copy)]
#[derive(Hash, PartialEq, Eq)]
#[derive(Ord, PartialOrd)]
#[derive(strum_macros::EnumString, strum_macros::EnumIter, strum_macros::Display)]
#[derive(serde::Serialize, serde::Deserialize)]
pub enum LevelShifterType {
#[strum(serialize = "LH")]
LH,
#[strum(serialize = "HL")]
HL,
#[strum(serialize = "HL_LH")]
HL_LH,
}
impl SimpleAttri for LevelShifterType {
#[inline]
fn nom_parse<'a>(i: &'a str, scope: &mut ParseScope) -> SimpleParseRes<'a, Self> {
crate::ast::nom_parse_from_str(i, scope)
}
}
#[derive(Debug, Clone)]
#[derive(Hash, PartialEq, Eq)]
#[derive(Ord, PartialOrd)]
#[derive(serde::Serialize, serde::Deserialize)]
pub enum ClockGatingIntegratedCell {
ContainlatchNegedge,
RegisterslatchPosedgePostcontrol,
LatchlatchNegedgePrecontrol,
LatchnonePosedgeControlObs,
Generic(ArcStr),
}
impl FromStr for ClockGatingIntegratedCell {
type Err = ();
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"containlatch_negedge" => Ok(Self::ContainlatchNegedge),
"registerslatch_posedge_postcontrol" => Ok(Self::RegisterslatchPosedgePostcontrol),
"latchlatch_negedge_precontrol" => Ok(Self::LatchlatchNegedgePrecontrol),
"latchnone_posedge_control_obs" => Ok(Self::LatchnonePosedgeControlObs),
_ => Ok(Self::Generic(s.into())),
}
}
}
impl fmt::Display for ClockGatingIntegratedCell {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::ContainlatchNegedge => write!(f, "containlatch_negedge"),
Self::RegisterslatchPosedgePostcontrol => {
write!(f, "registerslatch_posedge_postcontrol")
}
Self::LatchlatchNegedgePrecontrol => write!(f, "latchlatch_negedge_precontrol"),
Self::LatchnonePosedgeControlObs => write!(f, "latchnone_posedge_control_obs"),
Self::Generic(s) => write!(f, "{s}"),
}
}
}
impl SimpleAttri for ClockGatingIntegratedCell {
#[inline]
fn nom_parse<'a>(i: &'a str, scope: &mut ParseScope) -> SimpleParseRes<'a, Self> {
crate::ast::nom_parse_from_str(i, scope)
}
}
#[derive(Debug, Clone)]
#[derive(Hash, PartialEq, Eq)]
#[derive(Ord, PartialOrd)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct PinOpposite {
pub name_list1: WordSet,
pub name_list2: WordSet,
}
impl ComplexAttri for PinOpposite {
#[inline]
fn parse<'a, I: Iterator<Item = &'a &'a str>>(
mut iter: I,
_scope: &mut ParseScope,
) -> Result<Self, ComplexParseError> {
let name_list1: WordSet = match iter.next() {
Some(&s) => match s.parse() {
Ok(f) => f,
Err(_) => return Err(ComplexParseError::Other),
},
None => return Err(ComplexParseError::LengthDismatch),
};
let name_list2: WordSet = match iter.next() {
Some(&s) => match s.parse() {
Ok(f) => f,
Err(_) => return Err(ComplexParseError::Other),
},
None => return Err(ComplexParseError::LengthDismatch),
};
if iter.next().is_some() {
Err(ComplexParseError::LengthDismatch)
} else {
Ok(Self { name_list1, name_list2 })
}
}
#[inline]
fn fmt_self<T: Write, I: Indentation>(
&self,
f: &mut CodeFormatter<'_, T, I>,
) -> fmt::Result {
write!(f, "{}, {}", self.name_list1, self.name_list2)
}
}