1use crate::buffer::SignalBuffer;
6use crate::io::{
7 HeaderFinishInfo, update_header, write_geometry, write_header_meta_data, write_hierarchy_bytes,
8 write_hierarchy_scope, write_hierarchy_up_scope, write_hierarchy_var,
9};
10use crate::{
11 FstInfo, FstScopeType, FstSignalId, FstSignalType, FstVarDirection, FstVarType, Result,
12};
13
14pub fn open_fst<P: AsRef<std::path::Path>>(
15 path: P,
16 info: &FstInfo,
17) -> Result<FstHeaderWriter<std::io::BufWriter<std::fs::File>>> {
18 FstHeaderWriter::open(path, info)
19}
20
21pub struct FstHeaderWriter<W: std::io::Write + std::io::Seek> {
22 out: W,
23 hierarchy_buf: std::io::Cursor<Vec<u8>>,
25 signals: Vec<FstSignalType>,
26 scope_depth: u64,
27 var_count: u64,
28 scope_count: u64,
29}
30
31impl FstHeaderWriter<std::io::BufWriter<std::fs::File>> {
32 fn open<P: AsRef<std::path::Path>>(path: P, info: &FstInfo) -> Result<Self> {
33 let f = std::fs::File::create(path)?;
34 let mut out = std::io::BufWriter::new(f);
35 write_header_meta_data(&mut out, info)?;
36 Ok(Self {
37 out,
38 hierarchy_buf: std::io::Cursor::new(Vec::new()),
39 signals: vec![],
40 scope_depth: 0,
41 var_count: 0,
42 scope_count: 0,
43 })
44 }
45}
46
47impl<W: std::io::Write + std::io::Seek> FstHeaderWriter<W> {
48 pub fn scope(
49 &mut self,
50 name: impl AsRef<str>,
51 component: impl AsRef<str>,
52 tpe: FstScopeType,
53 ) -> Result<()> {
54 self.scope_depth += 1;
55 self.scope_count += 1;
56 write_hierarchy_scope(&mut self.hierarchy_buf, name, component, tpe)
57 }
58 pub fn up_scope(&mut self) -> Result<()> {
59 debug_assert!(self.scope_depth > 0, "no scope to pop");
60 self.scope_depth -= 1;
61 write_hierarchy_up_scope(&mut self.hierarchy_buf)
62 }
63
64 pub fn var(
65 &mut self,
66 name: impl AsRef<str>,
67 signal_tpe: FstSignalType,
68 tpe: FstVarType,
69 dir: FstVarDirection,
70 alias: Option<FstSignalId>,
71 ) -> Result<FstSignalId> {
72 self.var_count += 1;
73 write_hierarchy_var(&mut self.hierarchy_buf, tpe, dir, name, signal_tpe, alias)?;
74 if let Some(alias) = alias {
75 debug_assert!(alias.to_index() <= self.signals.len() as u32);
76 Ok(alias)
77 } else {
78 self.signals.push(signal_tpe);
79 let id = FstSignalId::from_index(self.signals.len() as u32);
80 Ok(id)
81 }
82 }
83
84 pub fn finish(mut self) -> Result<FstBodyWriter<W>> {
85 debug_assert_eq!(
86 self.scope_depth, 0,
87 "missing calls to up-scope to close all scopes!"
88 );
89 write_hierarchy_bytes(&mut self.out, &self.hierarchy_buf.into_inner())?;
90 write_geometry(&mut self.out, &self.signals)?;
91 let buffer = SignalBuffer::new(&self.signals)?;
92 let finish_info = HeaderFinishInfo {
93 end_time: 0, scope_count: self.scope_count,
95 var_count: self.var_count,
96 num_signals: self.signals.len() as u64,
97 num_value_change_sections: 0, };
99 let next = FstBodyWriter {
100 out: self.out,
101 buffer,
102 finish_info,
103 };
104 Ok(next)
105 }
106}
107
108pub struct FstBodyWriter<W: std::io::Write + std::io::Seek> {
109 out: W,
110 buffer: SignalBuffer,
111 finish_info: HeaderFinishInfo,
112}
113
114impl<W: std::io::Write + std::io::Seek> FstBodyWriter<W> {
115 pub fn time_change(&mut self, time: u64) -> Result<()> {
116 self.buffer.time_change(time)
117 }
118
119 pub fn signal_change(&mut self, signal_id: FstSignalId, value: &[u8]) -> Result<()> {
120 self.buffer.signal_change(signal_id, value)
121 }
122
123 pub fn flush(&mut self) -> Result<()> {
125 self.buffer.flush(&mut self.out)?;
126 self.finish_info.num_value_change_sections += 1;
127 Ok(())
128 }
129
130 pub fn size(&self) -> usize {
132 self.buffer.size()
133 }
134
135 pub fn finish(mut self) -> Result<()> {
136 let end_time = self.buffer.flush(&mut self.out)?;
138
139 self.finish_info.num_value_change_sections += 1;
141 self.finish_info.end_time = end_time;
142 update_header(&mut self.out, &self.finish_info)?;
143
144 Ok(())
145 }
146}