vcd/
write.rs

1use std::io;
2
3use crate::{
4    Command, Header, IdCode, ReferenceIndex, Scope, ScopeItem, ScopeType, SimulationCommand,
5    TimescaleUnit, Value, Var, VarType,
6};
7
8/// Struct wrapping an [`std::io::Write`] with methods for writing VCD commands and data.
9/// 
10/// ## Example
11/// ```rust,no_run
12/// # use std::error::Error;
13/// # fn main() -> Result<(), Box<dyn Error>> {
14/// use std::{fs::File, io::BufWriter};
15/// use vcd::{Value, TimescaleUnit};
16/// 
17/// let mut writer = vcd::Writer::new(BufWriter::new(File::create("test.vcd")?));
18/// 
19/// writer.timescale(1, TimescaleUnit::US)?;
20/// writer.add_module("top")?;
21/// let clock = writer.add_wire(1, "clock")?;
22/// writer.upscope()?;
23/// writer.enddefinitions()?;
24/// 
25/// let mut t = 0;
26/// while t < 100 {
27///     writer.timestamp(t)?;
28///     writer.change_scalar(clock, Value::V0)?;
29///     t += 2;
30/// 
31///     writer.timestamp(t)?;
32///     writer.change_scalar(clock, Value::V1)?;
33///     t += 2;
34/// }
35/// # Ok(()) }
36/// ```
37pub struct Writer<W: io::Write> {
38    writer: W,
39    next_id_code: IdCode,
40    scope_depth: usize,
41}
42
43impl<W: io::Write> Writer<W> {
44    /// Creates a Writer wrapping an [`io::Write`].
45    ///
46    /// ```
47    /// let mut buf = Vec::new();
48    /// let mut vcd = vcd::Writer::new(&mut buf);
49    /// ```
50    pub fn new(writer: W) -> Writer<W> {
51        Writer {
52            writer,
53            next_id_code: IdCode::FIRST,
54            scope_depth: 0,
55        }
56    }
57
58    /// Get the wrapped [`io::Write`].
59    pub fn writer(&mut self) -> &mut W {
60        &mut self.writer
61    }
62
63    /// Flush the wrapped [`io::Write`].
64    pub fn flush(&mut self) -> io::Result<()> {
65        self.writer.flush()
66    }
67
68    /// Writes a complete header with the fields from a [`Header`] struct from the parser.
69    pub fn header(&mut self, h: &Header) -> io::Result<()> {
70        if let Some(ref s) = h.date {
71            self.date(s)?;
72        }
73        if let Some(ref s) = h.version {
74            self.version(s)?;
75        }
76        if let Some((v, u)) = h.timescale {
77            self.timescale(v, u)?;
78        }
79        for i in &h.items {
80            match *i {
81                ScopeItem::Var(ref v) => self.var(v)?,
82                ScopeItem::Scope(ref s) => self.scope(s)?,
83                ScopeItem::Comment(ref c) => self.comment(c)?,
84            }
85        }
86        self.enddefinitions()
87    }
88
89    /// Writes a `$comment` command.
90    pub fn comment(&mut self, v: &str) -> io::Result<()> {
91        writeln!(self.writer, "$comment\n    {}\n$end", v)
92    }
93
94    /// Writes a `$date` command.
95    pub fn date(&mut self, v: &str) -> io::Result<()> {
96        writeln!(self.writer, "$date\n    {}\n$end", v)
97    }
98
99    /// Writes a `$version` command.
100    pub fn version(&mut self, v: &str) -> io::Result<()> {
101        writeln!(self.writer, "$version\n    {}\n$end", v)
102    }
103
104    /// Writes a `$timescale` command.
105    pub fn timescale(&mut self, ts: u32, unit: TimescaleUnit) -> io::Result<()> {
106        writeln!(self.writer, "$timescale {} {} $end", ts, unit)
107    }
108
109    /// Writes a `$scope` command.
110    pub fn scope_def(&mut self, t: ScopeType, i: &str) -> io::Result<()> {
111        self.scope_depth += 1;
112        writeln!(self.writer, "$scope {} {} $end", t, i)
113    }
114
115    /// Writes a `$scope` command for a module.
116    ///
117    /// Convenience wrapper around [`Writer::scope_def`].
118    pub fn add_module(&mut self, identifier: &str) -> io::Result<()> {
119        self.scope_def(ScopeType::Module, identifier)
120    }
121
122    /// Writes an `$upscope` command.
123    pub fn upscope(&mut self) -> io::Result<()> {
124        debug_assert!(
125            self.scope_depth > 0,
126            "Generating invalid VCD: upscope without a matching scope"
127        );
128        self.scope_depth -= 1;
129        writeln!(self.writer, "$upscope $end")
130    }
131
132    /// Writes a `$scope` command, a series of `$var` commands, and an
133    /// `$upscope` commands from a [`Scope`] structure from the parser.
134    pub fn scope(&mut self, s: &Scope) -> io::Result<()> {
135        self.scope_def(s.scope_type, &s.identifier[..])?;
136        for i in &s.items {
137            match *i {
138                ScopeItem::Var(ref v) => self.var(v)?,
139                ScopeItem::Scope(ref s) => self.scope(s)?,
140                ScopeItem::Comment(ref c) => self.comment(c)?,
141            }
142        }
143        self.upscope()
144    }
145
146    /// Writes a `$var` command with a specified id.
147    pub fn var_def(
148        &mut self,
149        var_type: VarType,
150        width: u32,
151        id: IdCode,
152        reference: &str,
153        index: Option<ReferenceIndex>,
154    ) -> io::Result<()> {
155        debug_assert!(
156            self.scope_depth > 0,
157            "Generating invalid VCD: variable must be in a scope"
158        );
159        if id >= self.next_id_code {
160            self.next_id_code = id.next();
161        }
162        match index {
163            Some(idx) => writeln!(
164                self.writer,
165                "$var {} {} {} {} {} $end",
166                var_type, width, id, reference, idx
167            ),
168            None => writeln!(
169                self.writer,
170                "$var {} {} {} {} $end",
171                var_type, width, id, reference
172            ),
173        }
174    }
175
176    /// Writes a `$var` command with the next available ID, returning the assigned ID.
177    ///
178    /// Convenience wrapper around [`Writer::var_def`].
179    pub fn add_var(
180        &mut self,
181        var_type: VarType,
182        width: u32,
183        reference: &str,
184        index: Option<ReferenceIndex>,
185    ) -> io::Result<IdCode> {
186        let id = self.next_id_code;
187        self.var_def(var_type, width, id, reference, index)?;
188        Ok(id)
189    }
190
191    /// Adds a `$var` for a wire with the next available ID, returning the assigned ID.
192    ///
193    /// Convenience wrapper around [`Writer::add_var`].
194    pub fn add_wire(&mut self, width: u32, reference: &str) -> io::Result<IdCode> {
195        self.add_var(VarType::Wire, width, reference, None)
196    }
197
198    /// Writes a `$var` command from a [`Var`] structure from the parser.
199    pub fn var(&mut self, v: &Var) -> io::Result<()> {
200        self.var_def(v.var_type, v.size, v.code, &v.reference[..], v.index)
201    }
202
203    /// Writes a `$enddefinitions` command to end the header.
204    pub fn enddefinitions(&mut self) -> io::Result<()> {
205        debug_assert!(
206            self.scope_depth == 0,
207            "Generating invalid VCD: {} scopes must be closed with $upscope before $enddefinitions",
208            self.scope_depth
209        );
210        writeln!(self.writer, "$enddefinitions $end")
211    }
212
213    /// Writes a `#xxx` timestamp.
214    pub fn timestamp(&mut self, ts: u64) -> io::Result<()> {
215        writeln!(self.writer, "#{}", ts)
216    }
217
218    /// Writes a change to a scalar variable.
219    pub fn change_scalar<V: Into<Value>>(&mut self, id: IdCode, v: V) -> io::Result<()> {
220        writeln!(self.writer, "{}{}", v.into(), id)
221    }
222
223    /// Writes a change to a vector variable.
224    pub fn change_vector(&mut self, id: IdCode, v: impl IntoIterator<Item=Value>) -> io::Result<()> {
225        write!(self.writer, "b")?;
226        for i in v {
227            write!(self.writer, "{}", i)?
228        }
229        writeln!(self.writer, " {}", id)
230    }
231
232    /// Writes a change to a real variable.
233    pub fn change_real(&mut self, id: IdCode, v: f64) -> io::Result<()> {
234        writeln!(self.writer, "r{} {}", v, id)
235    }
236
237    /// Writes a change to a string variable.
238    pub fn change_string(&mut self, id: IdCode, v: &str) -> io::Result<()> {
239        writeln!(self.writer, "s{} {}", v, id)
240    }
241
242    /// Writes the beginning of a simulation command.
243    pub fn begin(&mut self, c: SimulationCommand) -> io::Result<()> {
244        writeln!(self.writer, "${}", c)
245    }
246
247    /// Writes an `$end` to end a simulation command.
248    pub fn end(&mut self) -> io::Result<()> {
249        writeln!(self.writer, "$end")
250    }
251
252    /// Writes a command from a [`Command`] enum as parsed by the parser.
253    pub fn command(&mut self, c: &Command) -> io::Result<()> {
254        use Command::*;
255        match *c {
256            Comment(ref c) => self.comment(&c[..]),
257            Date(ref c) => self.date(&c[..]),
258            Version(ref c) => self.version(&c[..]),
259            Timescale(v, u) => self.timescale(v, u),
260            ScopeDef(t, ref i) => self.scope_def(t, &i[..]),
261            Upscope => self.upscope(),
262            VarDef(t, s, i, ref r, idx) => self.var_def(t, s, i, &r[..], idx),
263            Enddefinitions => self.enddefinitions(),
264            Timestamp(t) => self.timestamp(t),
265            ChangeScalar(i, v) => self.change_scalar(i, v),
266            ChangeVector(i, ref v) => self.change_vector(i, v),
267            ChangeReal(i, v) => self.change_real(i, v),
268            ChangeString(i, ref v) => self.change_string(i, v),
269            Begin(c) => self.begin(c),
270            End(_) => self.end(),
271        }
272    }
273}