netlist_db/
_impl_display.rs

1use core::fmt;
2use std::{borrow::Borrow as _, fmt::Display};
3
4use super::*;
5
6#[derive(Debug, Clone, Copy)]
7pub struct FloatDisplay(pub f64);
8impl fmt::Display for FloatDisplay {
9    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
10        write!(f, "{:.7e}", self.0)
11    }
12}
13
14pub struct TableFloatDisplay(pub f64);
15impl fmt::Display for TableFloatDisplay {
16    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
17        if self.0.is_sign_positive() {
18            write!(f, " {: <13.7e}", self.0)
19        } else {
20            write!(f, "{: <14.7e}", self.0)
21        }
22    }
23}
24
25pub struct OptionDispaly<'a, T, F: Fn(&T, &mut fmt::Formatter<'_>) -> fmt::Result>(
26    pub &'a Option<T>,
27    pub F,
28);
29impl<T, F: Fn(&T, &mut fmt::Formatter<'_>) -> fmt::Result> Display for OptionDispaly<'_, T, F> {
30    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
31        if let Some(t) = self.0 {
32            self.1(t, f)
33        } else {
34            Ok(())
35        }
36    }
37}
38
39pub fn display_wrap<
40    W: fmt::Write,
41    T,
42    I: Iterator<Item = T>,
43    SEP: fmt::Display,
44    F: FnMut(T, &mut W) -> fmt::Result,
45>(
46    f: &mut W,
47    iter: I,
48    mut fmt_one: F,
49    line_sep: SEP,
50    item_sep: char,
51    wrap_size: usize,
52) -> fmt::Result {
53    use itertools::Itertools as _;
54    for mut ts in iter.into_iter().chunks(wrap_size).into_iter() {
55        write!(f, "\n{line_sep}")?;
56        if let Some(first) = ts.next() {
57            fmt_one(first, f)?;
58            for t in ts {
59                write!(f, "{item_sep}")?;
60                fmt_one(t, f)?;
61            }
62        }
63    }
64    Ok(())
65}
66
67pub fn display_inline<
68    W: fmt::Write,
69    T,
70    I: Iterator<Item = T>,
71    F: FnMut(T, &mut W) -> fmt::Result,
72>(
73    f: &mut W,
74    iter: I,
75    mut fmt_one: F,
76    sep: char,
77    skip_first_sep: bool,
78) -> fmt::Result {
79    let mut iter = iter.into_iter();
80    if skip_first_sep {
81        if let Some(first) = iter.next() {
82            fmt_one(first, f)?;
83        }
84    }
85    for t in iter {
86        write!(f, "{sep}")?;
87        fmt_one(t, f)?;
88    }
89    Ok(())
90}
91
92pub fn display_multiline<
93    W: fmt::Write,
94    T,
95    I: Iterator<Item = T>,
96    F: FnMut(T, &mut W) -> fmt::Result,
97>(
98    f: &mut W,
99    iter: I,
100    mut fmt_one: F,
101) -> fmt::Result {
102    for t in iter.into_iter() {
103        writeln!(f)?;
104        fmt_one(t, f)?;
105    }
106    Ok(())
107}
108
109impl fmt::Display for AST<'_> {
110    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
111        DefaultFmt.ast(self, f)
112    }
113}
114impl fmt::Display for Subckt<'_> {
115    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
116        DefaultFmt.subckt(self, f)
117    }
118}
119
120#[derive(Debug, Clone, Copy)]
121pub struct DefaultFmt;
122impl SpiceFmt for DefaultFmt {}
123
124pub trait SpiceFmt: Sized {
125    fn value<W: fmt::Write>(&self, t: &ast::Value<'_>, f: &mut W) -> fmt::Result {
126        match t {
127            ast::Value::Num(float) => write!(f, "{}", FloatDisplay(*float)),
128            ast::Value::Expr(expr) => write!(f, "'{expr}'"),
129        }
130    }
131    fn key_value<W: fmt::Write>(&self, t: &ast::KeyValue<'_>, f: &mut W) -> fmt::Result {
132        write!(f, "{}=", t.k)?;
133        self.value(&t.v, f)
134    }
135    fn token<W: fmt::Write>(&self, t: &ast::Token<'_>, f: &mut W) -> fmt::Result {
136        match t {
137            ast::Token::KV(t) => self.key_value(t, f),
138            ast::Token::Value(t) => self.value(t, f),
139            ast::Token::V(name) => write!(f, "V({name})"),
140            ast::Token::I(name) => write!(f, "I({name})"),
141        }
142    }
143    fn data_files<W: fmt::Write>(&self, t: &ast::DataFiles<'_>, f: &mut W) -> fmt::Result {
144        display_multiline(f, t.files.iter(), |file, f| {
145            write!(f, "+ FILE='{}'", file.file)?;
146            display_inline(
147                f,
148                file.pname_col_num.iter(),
149                |pname_col_num, f| write!(f, "{}={}", pname_col_num.pname, pname_col_num.col_num),
150                ' ',
151                false,
152            )
153        })?;
154        write!(
155            f,
156            "{}",
157            OptionDispaly(&t.out, |out, f| write!(f, "\n+ OUT='{out}'")),
158        )
159    }
160    fn data<W: fmt::Write>(&self, t: &ast::Data<'_>, f: &mut W) -> fmt::Result {
161        write!(f, ".DATA {}", t.name)?;
162        match &t.values {
163            ast::DataValues::InlineExpr { params, values } => {
164                write!(f, "\n+",)?;
165                display_inline(f, params.iter(), |t, f| write!(f, "{t}"), ' ', false)?;
166                write!(f, " DATAFORM")?;
167                display_wrap(
168                    f,
169                    values.iter(),
170                    |t, f| self.value(t, f),
171                    "+ ",
172                    ' ',
173                    params.len(),
174                )?;
175            }
176            ast::DataValues::InlineNum { params, values } => {
177                write!(f, "\n+",)?;
178                display_inline(f, params.iter(), |t, f| write!(f, "{t}"), ' ', false)?;
179                display_wrap(
180                    f,
181                    values.iter(),
182                    |float, f| write!(f, "{}", FloatDisplay(*float)),
183                    "+ ",
184                    ' ',
185                    params.len(),
186                )?;
187            }
188            ast::DataValues::MER(t) => {
189                write!(f, " MER")?;
190                self.data_files(t, f)?;
191            }
192            ast::DataValues::LAM(t) => {
193                write!(f, " LAM")?;
194                self.data_files(t, f)?;
195            }
196        }
197        write!(f, "\n.ENDDATA")
198    }
199    fn instance<W: fmt::Write>(&self, t: &instance::Instance<'_>, f: &mut W) -> fmt::Result {
200        write!(f, "{} ", t.name)?;
201        self.instance_ctx(&t.ctx, f)
202    }
203    fn instance_ctx<W: fmt::Write>(&self, t: &instance::InstanceCtx<'_>, f: &mut W) -> fmt::Result {
204        match t {
205            instance::InstanceCtx::Resistor(t) => self.resistor(t, f),
206            instance::InstanceCtx::Capacitor(t) => self.capacitor(t, f),
207            instance::InstanceCtx::Inductor(t) => self.inductor(t, f),
208            instance::InstanceCtx::Voltage(t) => self.voltage(t, f),
209            instance::InstanceCtx::Current(t) => self.current(t, f),
210            instance::InstanceCtx::MOSFET(t) => self.mosfet(t, f),
211            instance::InstanceCtx::BJT(t) => self.bjt(t, f),
212            instance::InstanceCtx::Diode(t) => self.diode(t, f),
213            instance::InstanceCtx::Subckt(t) => self.inst_subckt(t, f),
214            instance::InstanceCtx::Unknown {
215                r#type: _,
216                nodes,
217                params,
218            } => {
219                display_inline(f, nodes.iter(), |t, f| write!(f, "{t}"), ' ', true)?;
220                display_inline(f, params.iter(), |t, f| self.key_value(t, f), ' ', false)
221            }
222        }
223    }
224    fn inst_subckt<W: fmt::Write>(&self, t: &instance::Subckt<'_>, f: &mut W) -> fmt::Result {
225        self.ports(t.nodes.iter().map(|s| s.borrow()), f)?;
226        write!(f, " {}", t.cktname)?;
227        display_inline(f, t.params.iter(), |t, f| self.key_value(t, f), ' ', false)
228    }
229    fn voltage<W: fmt::Write>(&self, t: &instance::Voltage<'_>, f: &mut W) -> fmt::Result {
230        write!(f, "{} {} ", t.n1, t.n2)?;
231        self.voltage_source(&t.source, f)
232    }
233    fn current<W: fmt::Write>(&self, t: &instance::Current<'_>, f: &mut W) -> fmt::Result {
234        write!(f, "{} {} ", t.n1, t.n2)?;
235        self.current_source(&t.source, f)
236    }
237    fn voltage_source<W: fmt::Write>(
238        &self,
239        t: &instance::VoltageSource<'_>,
240        f: &mut W,
241    ) -> fmt::Result {
242        match t {
243            instance::VoltageSource::Params(params) => {
244                display_inline(f, params.iter(), |t, f| self.key_value(t, f), ' ', false)
245            }
246            instance::VoltageSource::Value(t) => self.value(t, f),
247            instance::VoltageSource::PWL(t) => self.pwl(t, f),
248        }
249    }
250    fn current_source<W: fmt::Write>(
251        &self,
252        t: &instance::CurrentSource<'_>,
253        f: &mut W,
254    ) -> fmt::Result {
255        match t {
256            instance::CurrentSource::Params(params) => {
257                display_inline(f, params.iter(), |t, f| self.key_value(t, f), ' ', false)
258            }
259            instance::CurrentSource::Value(t) => self.value(t, f),
260            instance::CurrentSource::PWL(t) => self.pwl(t, f),
261        }
262    }
263    fn time_value_point<W: fmt::Write>(
264        &self,
265        t: &instance::TimeValuePoint<'_>,
266        f: &mut W,
267    ) -> fmt::Result {
268        self.value(&t.time, f)?;
269        write!(f, " ")?;
270        self.value(&t.value, f)
271    }
272    fn pwl<W: fmt::Write>(&self, t: &instance::PWL<'_>, f: &mut W) -> fmt::Result {
273        write!(f, "PWL(",)?;
274        display_wrap(
275            f,
276            t.points.iter(),
277            |t, f| self.time_value_point(t, f),
278            "+ ",
279            ' ',
280            1,
281        )?;
282        write!(f, ")",)
283    }
284    fn resistor<W: fmt::Write>(&self, t: &instance::Resistor<'_>, f: &mut W) -> fmt::Result {
285        write!(f, "{} {} ", t.n1, t.n2)?;
286        self.value(&t.value, f)
287    }
288    fn capacitor<W: fmt::Write>(&self, t: &instance::Capacitor<'_>, f: &mut W) -> fmt::Result {
289        write!(f, "{} {} ", t.n1, t.n2)?;
290        self.value(&t.value, f)
291    }
292    fn inductor<W: fmt::Write>(&self, t: &instance::Inductor<'_>, f: &mut W) -> fmt::Result {
293        write!(f, "{} {} ", t.n1, t.n2)?;
294        self.value(&t.value, f)
295    }
296    fn mosfet<W: fmt::Write>(&self, t: &instance::MOSFET<'_>, f: &mut W) -> fmt::Result {
297        write!(
298            f,
299            "{} {} {}{} {}",
300            t.nd,
301            t.ng,
302            t.ns,
303            OptionDispaly(&t.nb, |nb, f| write!(f, " {nb}")),
304            t.mname,
305        )?;
306        display_inline(f, t.params.iter(), |t, f| self.key_value(t, f), ' ', false)
307    }
308    fn bjt<W: fmt::Write>(&self, t: &instance::BJT<'_>, f: &mut W) -> fmt::Result {
309        write!(
310            f,
311            "{} {} {}{} {}",
312            t.nc,
313            t.nb,
314            t.ne,
315            OptionDispaly(&t.ns, |ns, f| write!(f, " {ns}")),
316            t.mname,
317        )?;
318        display_inline(f, t.params.iter(), |t, f| self.key_value(t, f), ' ', false)
319    }
320    fn diode<W: fmt::Write>(&self, t: &instance::Diode<'_>, f: &mut W) -> fmt::Result {
321        write!(f, "{} {} {}", t.nplus, t.nminus, t.mname,)?;
322        display_inline(f, t.params.iter(), |t, f| self.key_value(t, f), ' ', false)
323    }
324    fn model_type<W: fmt::Write>(&self, t: &ast::ModelType<'_>, f: &mut W) -> fmt::Result {
325        match t {
326            ast::ModelType::AMP => write!(f, "AMP"),
327            ast::ModelType::C => write!(f, "C"),
328            ast::ModelType::CORE => write!(f, "CORE"),
329            ast::ModelType::D => write!(f, "D"),
330            ast::ModelType::L => write!(f, "L"),
331            ast::ModelType::NJF => write!(f, "NJF"),
332            ast::ModelType::NMOS => write!(f, "NMOS"),
333            ast::ModelType::NPN => write!(f, "NPN"),
334            ast::ModelType::OPT => write!(f, "OPT"),
335            ast::ModelType::PJF => write!(f, "PJF"),
336            ast::ModelType::PMOS => write!(f, "PMOS"),
337            ast::ModelType::PNP => write!(f, "PNP"),
338            ast::ModelType::R => write!(f, "R"),
339            ast::ModelType::U => write!(f, "U"),
340            ast::ModelType::W => write!(f, "W"),
341            ast::ModelType::S => write!(f, "S"),
342            ast::ModelType::Unknown(span) => write!(f, "{span}"),
343        }
344    }
345    fn model<W: fmt::Write>(&self, t: &ast::Model<'_>, f: &mut W) -> fmt::Result {
346        write!(f, ".MODEL {} ", t.name)?;
347        self.model_type(&t.model_type, f)?;
348        display_wrap(
349            f,
350            t.params.iter(),
351            |t, f| self.key_value(t, f),
352            "+ ",
353            ' ',
354            4,
355        )
356    }
357    fn ports<'a, W: fmt::Write, I: Iterator<Item = &'a str>>(
358        &self,
359        t: I,
360        f: &mut W,
361    ) -> fmt::Result {
362        display_inline(f, t, |t, f| write!(f, "{t}"), ' ', true)
363    }
364    fn subckt<W: fmt::Write>(&self, t: &Subckt<'_>, f: &mut W) -> fmt::Result {
365        write!(f, ".SUBCKT {} ", t.name)?;
366        self.ports(t.ports.iter().map(|s| s.borrow()), f)?;
367        display_inline(f, t.params.iter(), |t, f| self.key_value(t, f), ' ', false)?;
368        self.ast(&t.ast, f)?;
369        write!(f, "\n.ENDS {}", t.name)
370    }
371    fn unknwon<W: fmt::Write>(&self, t: &ast::Unknwon<'_>, f: &mut W) -> fmt::Result {
372        write!(f, ".{}", t.cmd)?;
373        display_inline(f, t.tokens.iter(), |t, f| self.token(t, f), ' ', false)
374    }
375    fn general_cmd<W: fmt::Write>(&self, t: &ast::GeneralCmd, f: &mut W) -> fmt::Result {
376        _ = (t, f);
377        todo!()
378    }
379    fn general<W: fmt::Write>(&self, t: &ast::General<'_>, f: &mut W) -> fmt::Result {
380        write!(f, ".")?;
381        self.general_cmd(&t.cmd, f)?;
382        display_inline(f, t.tokens.iter(), |t, f| self.token(t, f), ' ', false)
383    }
384    fn ast<W: fmt::Write>(&self, t: &AST<'_>, f: &mut W) -> fmt::Result {
385        if !t.option.is_empty() {
386            write!(f, ".OPTION ",)?;
387            display_wrap(
388                f,
389                t.option.iter(),
390                |option, f| {
391                    if let Some(v) = &option.1 {
392                        write!(f, "{}=", option.0)?;
393                        self.value(v, f)
394                    } else {
395                        write!(f, "{}", option.0)
396                    }
397                },
398                "+ ",
399                ' ',
400                4,
401            )?;
402        }
403        if !t.param.is_empty() {
404            write!(f, "\n.PARAM ",)?;
405            display_wrap(f, t.param.iter(), |t, f| self.key_value(t, f), "+ ", ' ', 4)?;
406        }
407        display_multiline(f, t.model.iter(), |t, f| self.model(t, f))?;
408        display_multiline(f, t.subckt.values(), |t, f| self.subckt(t, f))?;
409        display_multiline(f, t.instance.iter(), |t, f| self.instance(t, f))?;
410        display_multiline(f, t.init_condition.iter(), |ic, f| {
411            write!(f, ".IC V({})=", ic.0)?;
412            self.value(&ic.1, f)?;
413            if let Some(subckt) = &ic.2 {
414                write!(f, " suckt={subckt}")
415            } else {
416                Ok(())
417            }
418        })?;
419        display_multiline(f, t.nodeset.iter(), |ic, f| {
420            write!(f, ".NODESET {}=", ic.0)?;
421            self.value(&ic.1, f)?;
422            if let Some(subckt) = &ic.2 {
423                write!(f, " suckt={subckt}")
424            } else {
425                Ok(())
426            }
427        })?;
428        display_multiline(f, t.data.iter(), |t, f| self.data(t, f))?;
429        display_multiline(f, t.general.iter(), |t, f| self.general(t, f))?;
430        display_multiline(f, t.unknwon.iter(), |t, f| self.unknwon(t, f))?;
431        Ok(())
432    }
433}