1use std::collections::{HashMap, HashSet};
2use std::fmt::Write;
3use std::sync::Arc;
4
5use derive_more::Debug;
6use eyre::{Result, anyhow, bail};
7use num::{BigUint, ToPrimitive};
8use surfer_translation_types::{
9 VariableDirection, VariableEncoding, VariableIndex, VariableType, VariableValue,
10};
11use tracing::warn;
12use wellen::{
13 FileFormat, Hierarchy, ScopeType, Signal, SignalEncoding, SignalRef, SignalSource, Time,
14 TimeTable, TimeTableIdx, Timescale, TimescaleUnit, Var, VarRef, VarType,
15};
16
17use crate::time::{TimeScale, TimeUnit};
18use crate::variable_direction::VariableDirectionExt;
19use crate::variable_index::VariableIndexExt;
20use crate::wave_container::{
21 MetaData, QueryResult, ScopeId, ScopeRef, ScopeRefExt, VarId, VariableMeta, VariableRef,
22 VariableRefExt,
23};
24
25static UNIQUE_ID_COUNT: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
26
27#[derive(Debug)]
28pub struct WellenContainer {
29 #[debug(skip)]
30 hierarchy: std::sync::Arc<Hierarchy>,
31 server: Option<String>,
33 scopes: Vec<String>,
34 vars: Vec<String>,
35 varrefs: Vec<VariableRef>,
36 signals: HashMap<SignalRef, Arc<Signal>>,
37 signals_to_be_loaded: HashSet<SignalRef>,
39 time_table: Arc<TimeTable>,
40 #[debug(skip)]
41 source: Option<SignalSource>,
42 unique_id: u64,
43 body_loaded: bool,
44}
45
46pub struct LoadSignalsCmd {
49 signals: Vec<SignalRef>,
50 from_unique_id: u64,
51 payload: LoadSignalPayload,
52}
53
54pub enum HeaderResult {
55 LocalFile(Box<wellen::viewers::HeaderResult<std::io::BufReader<std::fs::File>>>),
57 LocalBytes(Box<wellen::viewers::HeaderResult<std::io::Cursor<Vec<u8>>>>),
59 Remote(std::sync::Arc<Hierarchy>, FileFormat, String, usize),
61}
62
63pub enum BodyResult {
64 Local(wellen::viewers::BodyResult),
66 Remote(Vec<wellen::Time>, String),
68}
69
70pub enum LoadSignalPayload {
71 Local(SignalSource, std::sync::Arc<Hierarchy>),
72 Remote(String),
73}
74
75impl LoadSignalsCmd {
76 #[must_use]
77 pub fn destruct(self) -> (Vec<SignalRef>, u64, LoadSignalPayload) {
78 (self.signals, self.from_unique_id, self.payload)
79 }
80}
81
82pub struct LoadSignalsResult {
83 source: Option<SignalSource>,
84 server: Option<String>,
85 signals: Vec<(SignalRef, Signal)>,
86 from_unique_id: u64,
87}
88
89impl LoadSignalsResult {
90 #[must_use]
91 pub fn local(
92 source: SignalSource,
93 signals: Vec<(SignalRef, Signal)>,
94 from_unique_id: u64,
95 ) -> Self {
96 Self {
97 source: Some(source),
98 server: None,
99 signals,
100 from_unique_id,
101 }
102 }
103
104 #[must_use]
105 pub fn remote(server: String, signals: Vec<(SignalRef, Signal)>, from_unique_id: u64) -> Self {
106 Self {
107 source: None,
108 server: Some(server),
109 signals,
110 from_unique_id,
111 }
112 }
113
114 #[must_use]
115 pub fn len(&self) -> usize {
116 self.signals.len()
117 }
118
119 #[must_use]
120 pub fn is_empty(&self) -> bool {
121 self.signals.is_empty()
122 }
123}
124
125#[must_use]
126pub fn convert_format(format: FileFormat) -> crate::WaveFormat {
127 match format {
128 FileFormat::Vcd => crate::WaveFormat::Vcd,
129 FileFormat::Fst => crate::WaveFormat::Fst,
130 FileFormat::Ghw => crate::WaveFormat::Ghw,
131 FileFormat::Unknown => unreachable!("should never get here"),
132 }
133}
134
135impl WellenContainer {
136 pub fn new(hierarchy: std::sync::Arc<Hierarchy>, server: Option<String>) -> Self {
137 let h = &hierarchy;
139 let scopes = h.iter_scopes().map(|r| r.full_name(h)).collect::<Vec<_>>();
140 let vars: Vec<String> = h.iter_vars().map(|r| r.full_name(h)).collect::<Vec<_>>();
141 let varrefs = vars
142 .iter()
143 .enumerate()
144 .filter_map(|(n, name)| {
145 let r = VarRef::from_index(n).unwrap();
146 if h[r].var_type().is_parameter() {
147 return None;
148 }
149 Some(VariableRef::from_hierarchy_string_with_id(
150 name,
151 VarId::Wellen(r),
152 ))
153 })
154 .collect::<Vec<_>>();
155
156 let unique_id = UNIQUE_ID_COUNT.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
157
158 Self {
159 hierarchy,
160 server,
161 scopes,
162 vars,
163 varrefs,
164 signals: HashMap::new(),
165 signals_to_be_loaded: HashSet::new(),
166 time_table: Arc::new(vec![]),
167 source: None,
168 unique_id,
169 body_loaded: false,
170 }
171 }
172
173 #[must_use]
174 pub fn body_loaded(&self) -> bool {
175 self.body_loaded
176 }
177
178 pub fn add_body(&mut self, body: BodyResult) -> Result<Option<LoadSignalsCmd>> {
179 if self.body_loaded {
180 bail!("Did we just parse the body twice? That should not happen!");
181 }
182 match body {
183 BodyResult::Local(body) => {
184 if self.server.is_some() {
185 bail!(
186 "We are connected to a server, but also received the result of parsing a file locally. Something is going wrong here!"
187 );
188 }
189 self.time_table = Arc::new(body.time_table);
190 self.source = Some(body.source);
191 }
192 BodyResult::Remote(time_table, server) => {
193 if let Some(old) = &self.server {
194 if old != &server {
195 bail!("Inconsistent server URLs: {old} vs. {server}")
196 }
197 } else {
198 bail!("Missing server URL!");
199 }
200 self.time_table = Arc::new(time_table);
201 }
202 }
203 self.body_loaded = true;
204
205 Ok(self.load_signals(&[]))
208 }
209
210 #[must_use]
211 pub fn metadata(&self) -> MetaData {
212 let timescale = self
213 .hierarchy
214 .timescale()
215 .unwrap_or(Timescale::new(1, TimescaleUnit::Unknown));
216 let date = None;
217 MetaData {
218 date,
219 version: Some(self.hierarchy.version().to_string()),
220 timescale: TimeScale {
221 unit: TimeUnit::from(timescale.unit),
222 multiplier: Some(timescale.factor),
223 },
224 }
225 }
226
227 #[must_use]
228 pub fn max_timestamp(&self) -> Option<BigUint> {
229 self.time_table.last().map(|t| BigUint::from(*t))
230 }
231
232 #[must_use]
233 pub fn is_fully_loaded(&self) -> bool {
234 (self.source.is_some() || self.server.is_some()) && self.signals_to_be_loaded.is_empty()
235 }
236
237 #[must_use]
238 pub fn variable_names(&self) -> Vec<String> {
239 self.vars.clone()
240 }
241
242 fn lookup_scope(&self, scope: &ScopeRef) -> Option<wellen::ScopeRef> {
243 match scope.id {
244 ScopeId::Wellen(id) => Some(id),
245 ScopeId::None => self.hierarchy.lookup_scope(scope.strs()),
246 }
247 }
248
249 fn has_scope(&self, scope: &ScopeRef) -> bool {
250 match scope.id {
251 ScopeId::Wellen(_) => true,
252 ScopeId::None => self.hierarchy.lookup_scope(scope.strs()).is_some(),
253 }
254 }
255
256 #[must_use]
257 pub fn get_scope_type(&self, scope: &ScopeRef) -> Option<ScopeType> {
258 self.lookup_scope(scope)
259 .map(|scope_ref| self.hierarchy[scope_ref].scope_type())
260 }
261
262 #[must_use]
263 pub fn variables(&self) -> Vec<VariableRef> {
264 self.varrefs.clone()
265 }
266
267 pub fn variables_in_scope(&self, scope_ref: &ScopeRef) -> Vec<VariableRef> {
268 let h = &self.hierarchy;
269 if scope_ref.has_empty_strs() {
271 h.vars()
272 .filter(|id| !h[*id].var_type().is_parameter())
273 .map(|id| {
274 VariableRef::new_with_id(
275 scope_ref.clone(),
276 h[id].name(h).to_string(),
277 VarId::Wellen(id),
278 )
279 })
280 .collect::<Vec<_>>()
281 } else {
282 let scope = if let Some(id) = self.lookup_scope(scope_ref) {
283 &h[id]
284 } else {
285 warn!("Found no scope '{scope_ref}'. Defaulting to no variables");
286 return vec![];
287 };
288 scope
289 .vars(h)
290 .filter(|id| !h[*id].var_type().is_parameter())
291 .map(|id| {
292 VariableRef::new_with_id(
293 scope_ref.clone(),
294 h[id].name(h).to_string(),
295 VarId::Wellen(id),
296 )
297 })
298 .collect::<Vec<_>>()
299 }
300 }
301
302 pub fn parameters_in_scope(&self, scope_ref: &ScopeRef) -> Vec<VariableRef> {
303 let h = &self.hierarchy;
304 if scope_ref.strs().is_empty() {
306 h.vars()
307 .filter(|id| h[*id].var_type().is_parameter())
308 .map(|id| {
309 VariableRef::new_with_id(
310 scope_ref.clone(),
311 h[id].name(h).to_string(),
312 VarId::Wellen(id),
313 )
314 })
315 .collect::<Vec<_>>()
316 } else {
317 let scope = if let Some(id) = self.lookup_scope(scope_ref) {
318 &h[id]
319 } else {
320 warn!("Found no scope '{scope_ref}'. Defaulting to no variables");
321 return vec![];
322 };
323 scope
324 .vars(h)
325 .filter(|id| h[*id].var_type().is_parameter())
326 .map(|id| {
327 VariableRef::new_with_id(
328 scope_ref.clone(),
329 h[id].name(h).to_string(),
330 VarId::Wellen(id),
331 )
332 })
333 .collect::<Vec<_>>()
334 }
335 }
336
337 pub fn no_variables_in_scope(&self, scope_ref: &ScopeRef) -> bool {
338 let h = &self.hierarchy;
339 if scope_ref.has_empty_strs() {
341 h.vars().next().is_none()
342 } else {
343 let scope = if let Some(id) = self.lookup_scope(scope_ref) {
344 &h[id]
345 } else {
346 warn!("Found no scope '{scope_ref}'. Defaulting to no variables");
347 return true;
348 };
349 scope.vars(h).next().is_none()
350 }
351 }
352
353 #[must_use]
354 pub fn update_variable_ref(&self, variable: &VariableRef) -> Option<VariableRef> {
355 let h = &self.hierarchy;
357
358 let (var, new_scope_ref) = if variable.path.has_empty_strs() {
359 let var = h.lookup_var(&[], &variable.name)?;
360 (var, variable.path.clone())
361 } else {
362 let scope = h.lookup_scope(variable.path.strs())?;
364 let new_scope_ref = variable.path.with_id(ScopeId::Wellen(scope));
365
366 let var = h[scope].vars(h).find(|r| h[*r].name(h) == variable.name)?;
368 (var, new_scope_ref)
369 };
370
371 let new_variable_ref =
372 VariableRef::new_with_id(new_scope_ref, variable.name.clone(), VarId::Wellen(var));
373 Some(new_variable_ref)
374 }
375
376 pub fn get_var(&self, r: &VariableRef) -> Result<&Var> {
377 let h = &self.hierarchy;
378 self.get_var_ref(r).map(|r| &h[r])
379 }
380
381 #[must_use]
382 pub fn get_enum_map(&self, v: &Var) -> HashMap<String, String> {
383 match v.enum_type(&self.hierarchy) {
384 None => HashMap::new(),
385 Some((_, mapping)) => HashMap::from_iter(
386 mapping
387 .into_iter()
388 .map(|(k, v)| (k.to_string(), v.to_string())),
389 ),
390 }
391 }
392
393 fn get_var_ref(&self, r: &VariableRef) -> Result<VarRef> {
394 match r.id {
395 VarId::Wellen(id) => Ok(id),
396 VarId::None => {
397 let h = &self.hierarchy;
398 let Some(var) = h.lookup_var(r.path.strs(), r.name.clone()) else {
399 bail!("Failed to find variable: {r:?}")
400 };
401 Ok(var)
402 }
403 }
404 }
405
406 pub fn load_variables<S: AsRef<VariableRef>, T: Iterator<Item = S>>(
407 &mut self,
408 variables: T,
409 ) -> Result<Option<LoadSignalsCmd>> {
410 let h = &self.hierarchy;
411 let signal_refs = variables
412 .flat_map(|s| {
413 let r = s.as_ref();
414 self.get_var_ref(r).map(|v| h[v].signal_ref())
415 })
416 .collect::<Vec<_>>();
417 Ok(self.load_signals(&signal_refs))
418 }
419
420 pub fn load_all_params(&mut self) -> Result<Option<LoadSignalsCmd>> {
421 let h = &self.hierarchy;
422 let params = h
423 .iter_vars()
424 .filter(|r| r.var_type().is_parameter())
425 .map(wellen::Var::signal_ref)
426 .collect::<Vec<_>>();
427 Ok(self.load_signals(¶ms))
428 }
429
430 pub fn on_signals_loaded(&mut self, res: LoadSignalsResult) -> Result<Option<LoadSignalsCmd>> {
431 if res.from_unique_id == self.unique_id {
433 debug_assert!(self.source.is_none());
435 debug_assert!(self.server.is_none());
436 self.source = res.source;
437 self.server = res.server;
438 debug_assert!(self.server.is_some() || self.source.is_some());
439 for (id, signal) in res.signals {
441 self.signals.insert(id, Arc::new(signal));
442 }
443 }
444
445 Ok(self.load_signals(&[]))
447 }
448
449 fn load_signals(&mut self, ids: &[SignalRef]) -> Option<LoadSignalsCmd> {
450 let filtered_ids = ids
452 .iter()
453 .filter(|id| !self.signals.contains_key(id) && !self.signals_to_be_loaded.contains(id))
454 .copied()
455 .collect::<Vec<_>>();
456
457 self.signals_to_be_loaded.extend(filtered_ids.iter());
459
460 if self.signals_to_be_loaded.is_empty() {
461 return None; }
463
464 if !self.body_loaded {
465 return None; }
467
468 if let Some(server) = std::mem::take(&mut self.server) {
470 let mut signals = self.signals_to_be_loaded.drain().collect::<Vec<_>>();
472 signals.sort(); let cmd = LoadSignalsCmd {
474 signals,
475 payload: LoadSignalPayload::Remote(server),
476 from_unique_id: self.unique_id,
477 };
478 Some(cmd)
479 } else if let Some(source) = std::mem::take(&mut self.source) {
480 let mut signals = self.signals_to_be_loaded.drain().collect::<Vec<_>>();
482 signals.sort(); let cmd = LoadSignalsCmd {
484 signals,
485 payload: LoadSignalPayload::Local(source, self.hierarchy.clone()),
486 from_unique_id: self.unique_id,
487 };
488 Some(cmd)
489 } else {
490 None
491 }
492 }
493
494 fn time_to_time_table_idx(&self, time: &BigUint) -> Option<TimeTableIdx> {
495 let time: Time = time.to_u64().expect("unsupported time!");
496 let table = &self.time_table;
497 if table.is_empty() || table[0] > time {
498 None
499 } else {
500 let idx = binary_search(table, time);
502 assert!(table[idx] <= time);
503 Some(idx as TimeTableIdx)
504 }
505 }
506
507 pub fn query_variable(
508 &self,
509 variable: &VariableRef,
510 time: &BigUint,
511 ) -> Result<Option<QueryResult>> {
512 let h = &self.hierarchy;
513 let var_ref = self.get_var_ref(variable)?;
515 let signal_ref = h[var_ref].signal_ref();
517 let Some(sig) = self.signals.get(&signal_ref) else {
518 return Ok(None);
520 };
521 let time_table = &self.time_table;
522
523 if let Some(idx) = self.time_to_time_table_idx(time) {
525 if let Some(offset) = sig.get_offset(idx) {
527 let offset_time_idx = sig.get_time_idx_at(&offset);
529 let offset_time = time_table[offset_time_idx as usize];
530 let current_value = sig.get_value_at(&offset, offset.elements - 1);
532 let next_time = offset
534 .next_index
535 .and_then(|i| time_table.get(i.get() as usize));
536
537 let converted_value = convert_variable_value(current_value);
538 let result = QueryResult {
539 current: Some((BigUint::from(offset_time), converted_value)),
540 next: next_time.map(|t| BigUint::from(*t)),
541 };
542 return Ok(Some(result));
543 }
544 }
545
546 let first_index = sig.get_first_time_idx();
548 let next_time = first_index.and_then(|i| time_table.get(i as usize));
549 let result = QueryResult {
550 current: None,
551 next: next_time.map(|t| BigUint::from(*t)),
552 };
553 Ok(Some(result))
554 }
555
556 #[must_use]
557 pub fn scope_names(&self) -> Vec<String> {
558 self.scopes.clone()
559 }
560
561 #[must_use]
562 pub fn root_scopes(&self) -> Vec<ScopeRef> {
563 let h = &self.hierarchy;
564 h.scopes()
565 .map(|id| ScopeRef::from_strs_with_id(&[h[id].name(h)], ScopeId::Wellen(id)))
566 .collect::<Vec<_>>()
567 }
568
569 pub fn child_scopes(&self, scope_ref: &ScopeRef) -> Result<Vec<ScopeRef>> {
570 let h = &self.hierarchy;
571 let scope = match self.lookup_scope(scope_ref) {
572 Some(id) => &h[id],
573 None => return Err(anyhow!("Failed to find scope {scope_ref:?}")),
574 };
575 Ok(scope
576 .scopes(h)
577 .map(|id| scope_ref.with_subscope(h[id].name(h).to_string(), ScopeId::Wellen(id)))
578 .collect::<Vec<_>>())
579 }
580
581 #[must_use]
582 pub fn scope_exists(&self, scope: &ScopeRef) -> bool {
583 scope.has_empty_strs() | self.has_scope(scope)
584 }
585
586 #[must_use]
587 pub fn scope_is_variable(&self, scope: &ScopeRef) -> bool {
589 if let Some(scope_ref) = self.lookup_scope(scope) {
590 let h = &self.hierarchy;
591 let scope = &h[scope_ref];
592 matches!(
593 scope.scope_type(),
594 ScopeType::Struct
595 | ScopeType::Union
596 | ScopeType::Class
597 | ScopeType::Interface
598 | ScopeType::VhdlRecord
599 | ScopeType::VhdlArray
600 )
601 } else {
602 false
603 }
604 }
605
606 #[must_use]
607 pub fn get_scope_tooltip_data(&self, scope: &ScopeRef) -> String {
608 let mut out = String::new();
609 if let Some(scope_ref) = self.lookup_scope(scope) {
610 let h = &self.hierarchy;
611 let scope = &h[scope_ref];
612 writeln!(&mut out, "{}", scope_type_to_string(scope.scope_type())).unwrap();
613 if let Some((path, line)) = scope.instantiation_source_loc(h) {
614 writeln!(&mut out, "{path}:{line}").unwrap();
615 }
616 match (scope.component(h), scope.source_loc(h)) {
617 (Some(name), Some((path, line))) => {
618 write!(&mut out, "{name} : {path}:{line}").unwrap();
619 }
620 (None, Some((path, line))) => {
621 let same = scope
623 .instantiation_source_loc(h)
624 .is_some_and(|(i_path, i_line)| path == i_path && line == i_line);
625 if !same {
626 write!(&mut out, "{path}:{line}").unwrap();
627 }
628 }
629 (Some(name), None) => write!(&mut out, "{name}").unwrap(),
630 (None, None) => {}
632 }
633 }
634 if out.ends_with('\n') {
635 out.pop().unwrap();
636 }
637 out
638 }
639
640 pub fn variable_to_meta(&self, variable: &VariableRef) -> Result<VariableMeta> {
641 let var = self.get_var(variable)?;
642 let encoding = match var.signal_encoding() {
643 SignalEncoding::String => VariableEncoding::String,
644 SignalEncoding::Real => VariableEncoding::Real,
645 SignalEncoding::BitVector(_) => VariableEncoding::BitVector,
646 SignalEncoding::Event => VariableEncoding::Event,
647 };
648 Ok(VariableMeta {
649 var: variable.clone(),
650 num_bits: var.length(),
651 variable_type: Some(VariableType::from_wellen_type(var.var_type())),
652 variable_type_name: var.vhdl_type_name(&self.hierarchy).map(ToString::to_string),
653 index: var.index().map(VariableIndex::from_wellen_type),
654 direction: Some(VariableDirection::from_wellen_direction(var.direction())),
655 enum_map: self.get_enum_map(var),
656 encoding,
657 })
658 }
659
660 pub fn signal_accessor(&self, signal_ref: SignalRef) -> Result<WellenSignalAccessor> {
661 let signal = self
662 .signals
663 .get(&signal_ref)
664 .cloned()
665 .ok_or_else(|| anyhow!("Signal not loaded"))?;
666 Ok(WellenSignalAccessor::new(
667 signal,
668 Arc::clone(&self.time_table),
669 ))
670 }
671
672 pub fn signal_ref(&self, variable: &VariableRef) -> Result<SignalRef> {
674 let var_ref = self.get_var_ref(variable)?;
675 Ok(self.hierarchy[var_ref].signal_ref())
676 }
677
678 #[must_use]
680 pub fn is_signal_loaded(&self, signal_ref: SignalRef) -> bool {
681 self.signals.contains_key(&signal_ref)
682 }
683}
684
685pub struct WellenSignalAccessor {
687 signal: Arc<Signal>,
688 time_table: Arc<TimeTable>,
689}
690
691impl WellenSignalAccessor {
692 #[must_use]
694 pub fn new(signal: Arc<Signal>, time_table: Arc<TimeTable>) -> Self {
695 Self { signal, time_table }
696 }
697
698 #[must_use]
700 pub fn iter_changes(
701 &self,
702 ) -> Box<dyn Iterator<Item = (u64, surfer_translation_types::VariableValue)> + '_> {
703 Box::new(
704 self.signal
705 .iter_changes()
706 .filter_map(|(time_idx, signal_value)| {
707 let time_u64 = *self.time_table.get(time_idx as usize)?;
708 let var_value = convert_variable_value(signal_value);
709 Some((time_u64, var_value))
710 }),
711 )
712 }
713}
714
715fn scope_type_to_string(tpe: ScopeType) -> &'static str {
716 match tpe {
717 ScopeType::Module => "module",
718 ScopeType::Task => "task",
719 ScopeType::Function => "function",
720 ScopeType::Begin => "begin",
721 ScopeType::Fork => "fork",
722 ScopeType::Generate => "generate",
723 ScopeType::Struct => "struct",
724 ScopeType::Union => "union",
725 ScopeType::Class => "class",
726 ScopeType::Interface => "interface",
727 ScopeType::Package => "package",
728 ScopeType::Program => "program",
729 ScopeType::VhdlArchitecture => "architecture",
730 ScopeType::VhdlProcedure => "procedure",
731 ScopeType::VhdlFunction => "function",
732 ScopeType::VhdlRecord => "record",
733 ScopeType::VhdlProcess => "process",
734 ScopeType::VhdlBlock => "block",
735 ScopeType::VhdlForGenerate => "for-generate",
736 ScopeType::VhdlIfGenerate => "if-generate",
737 ScopeType::VhdlGenerate => "generate",
738 ScopeType::VhdlPackage => "package",
739 ScopeType::GhwGeneric => "generic",
740 ScopeType::VhdlArray => "array",
741 ScopeType::Unknown => "unknown",
742 _ => todo!(),
743 }
744}
745
746fn convert_variable_value(value: wellen::SignalValue) -> VariableValue {
747 match value {
748 wellen::SignalValue::Binary(data, _bits) => {
749 VariableValue::BigUint(BigUint::from_bytes_be(data))
750 }
751 wellen::SignalValue::FourValue(_, _) | wellen::SignalValue::NineValue(_, _) => {
752 VariableValue::String(
753 value
754 .to_bit_string()
755 .expect("failed to convert value {value:?} to a string"),
756 )
757 }
758 wellen::SignalValue::String(value) => VariableValue::String(value.to_string()),
759 wellen::SignalValue::Real(value) => VariableValue::BigUint(BigUint::from(value.to_bits())),
760 wellen::SignalValue::Event => VariableValue::String("Event".to_string()),
761 }
762}
763
764#[local_impl::local_impl]
765impl FromVarType for VariableType {
766 fn from_wellen_type(signaltype: VarType) -> Self {
767 match signaltype {
768 VarType::Reg => VariableType::VCDReg,
769 VarType::Wire => VariableType::VCDWire,
770 VarType::Integer => VariableType::VCDInteger,
771 VarType::Real => VariableType::VCDReal,
772 VarType::Parameter => VariableType::VCDParameter,
773 VarType::String => VariableType::VCDString,
774 VarType::Time => VariableType::VCDTime,
775 VarType::Event => VariableType::VCDEvent,
776 VarType::Supply0 => VariableType::VCDSupply0,
777 VarType::Supply1 => VariableType::VCDSupply1,
778 VarType::Tri => VariableType::VCDTri,
779 VarType::TriAnd => VariableType::VCDTriAnd,
780 VarType::TriOr => VariableType::VCDTriOr,
781 VarType::TriReg => VariableType::VCDTriReg,
782 VarType::Tri0 => VariableType::VCDTri0,
783 VarType::Tri1 => VariableType::VCDTri1,
784 VarType::WAnd => VariableType::VCDWAnd,
785 VarType::WOr => VariableType::VCDWOr,
786 VarType::Port => VariableType::Port,
787 VarType::Bit => VariableType::Bit,
788 VarType::Logic => VariableType::Logic,
789 VarType::Int => VariableType::VCDInteger,
790 VarType::Enum => VariableType::Enum,
791 VarType::SparseArray => VariableType::SparseArray,
792 VarType::RealTime => VariableType::RealTime,
793 VarType::ShortInt => VariableType::ShortInt,
794 VarType::LongInt => VariableType::LongInt,
795 VarType::Byte => VariableType::Byte,
796 VarType::ShortReal => VariableType::ShortReal,
797 VarType::Boolean => VariableType::Boolean,
798 VarType::BitVector => VariableType::BitVector,
799 VarType::StdLogic => VariableType::StdLogic,
800 VarType::StdLogicVector => VariableType::StdLogicVector,
801 VarType::StdULogic => VariableType::StdULogic,
802 VarType::StdULogicVector => VariableType::StdULogicVector,
803 VarType::RealParameter => VariableType::RealParameter,
804 }
805 }
806}
807
808#[local_impl::local_impl]
809impl VarTypeExt for VarType {
810 fn is_parameter(&self) -> bool {
811 matches!(self, VarType::Parameter | VarType::RealParameter)
812 }
813}
814
815#[inline]
816fn binary_search(times: &[Time], needle: Time) -> usize {
817 let mut lower_idx = 0usize;
818 let mut upper_idx = times.len() - 1;
819 while lower_idx <= upper_idx {
820 let mid_idx = lower_idx + ((upper_idx - lower_idx) / 2);
821
822 match times[mid_idx].cmp(&needle) {
823 std::cmp::Ordering::Less => {
824 lower_idx = mid_idx + 1;
825 }
826 std::cmp::Ordering::Equal => {
827 return mid_idx;
828 }
829 std::cmp::Ordering::Greater => {
830 upper_idx = mid_idx - 1;
831 }
832 }
833 }
834 lower_idx - 1
835}
836
837#[cfg(test)]
838mod tests {
839 use super::*;
840
841 #[test]
842 fn test_signal_conversion() {
843 let inp0: &[u8] = &[128, 0, 0, 3];
844 let out0 = convert_variable_value(wellen::SignalValue::Binary(inp0, 32));
845 assert_eq!(out0, VariableValue::BigUint(BigUint::from(0x80000003u64)));
846 }
847}