1use std::sync::Mutex;
2
3use chrono::prelude::{DateTime, Utc};
4use eyre::{Result, bail};
5use num::BigUint;
6use serde::{Deserialize, Serialize};
7use surfer_translation_types::VariableValue;
8
9use crate::cxxrtl_container::CxxrtlContainer;
10#[cfg(not(target_arch = "wasm32"))]
11use crate::fst_export::FstExport;
12use crate::time::{TimeScale, TimeUnit};
13use crate::wellen::{BodyResult, LoadSignalsCmd, LoadSignalsResult, WellenContainer};
14
15pub type FieldRef = surfer_translation_types::FieldRef<VarId, ScopeId>;
16pub type ScopeRef = surfer_translation_types::ScopeRef<ScopeId>;
17pub type VariableRef = surfer_translation_types::VariableRef<VarId, ScopeId>;
18pub type VariableMeta = surfer_translation_types::VariableMeta<VarId, ScopeId>;
19
20pub type AnalogCacheKey = (SignalId, String);
22
23#[derive(Debug, Clone)]
24pub enum SimulationStatus {
25 Paused,
26 Running,
27 Finished,
28}
29
30pub struct MetaData {
31 pub date: Option<DateTime<Utc>>,
32 pub version: Option<String>,
33 pub timescale: TimeScale,
34}
35
36#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
38pub enum ScopeId {
39 #[default]
40 None,
41 Wellen(wellen::ScopeRef),
42}
43
44#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
46pub enum VarId {
47 #[default]
48 None,
49 Wellen(wellen::VarRef),
50}
51
52#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
55pub enum SignalId {
56 #[default]
57 None,
58 Wellen(wellen::SignalRef),
59}
60
61pub enum SignalAccessor {
64 Wellen(crate::wellen::WellenSignalAccessor),
65 }
67
68impl SignalAccessor {
69 pub fn iter_changes(&self) -> Box<dyn Iterator<Item = (u64, VariableValue)> + '_> {
71 match self {
72 SignalAccessor::Wellen(accessor) => accessor.iter_changes(),
73 }
74 }
75}
76
77#[derive(Debug, Default)]
78pub struct QueryResult {
79 pub current: Option<(BigUint, VariableValue)>,
80 pub next: Option<BigUint>,
81}
82
83#[local_impl::local_impl]
84impl ScopeRefExt for ScopeRef {
85 fn empty() -> Self {
86 Self {
87 strs: vec![],
88 id: ScopeId::default(),
89 }
90 }
91
92 fn from_strs<S: ToString>(s: &[S]) -> Self {
93 Self::from_strs_with_id(s, ScopeId::default())
94 }
95
96 fn from_strs_with_id(s: &[impl ToString], id: ScopeId) -> Self {
97 let strs = s.iter().map(ToString::to_string).collect();
98 Self { strs, id }
99 }
100
101 fn from_hierarchy_string(s: &str) -> Self {
103 let strs = s.split('.').map(ToString::to_string).collect();
104 let id = ScopeId::default();
105 Self { strs, id }
106 }
107
108 fn with_subscope(&self, subscope: String, id: ScopeId) -> Self {
109 let mut result = self.clone();
110 result.strs.push(subscope);
111 result.id = id;
113 result
114 }
115
116 fn name(&self) -> String {
117 self.strs.last().cloned().unwrap_or_default()
118 }
119
120 fn full_name(&self) -> String {
121 self.strs.join(".")
122 }
123
124 fn strs(&self) -> &[String] {
125 &self.strs
126 }
127
128 fn with_id(&self, id: ScopeId) -> Self {
129 let mut out = self.clone();
130 out.id = id;
131 out
132 }
133
134 fn cxxrtl_repr(&self) -> String {
135 self.strs.join(" ")
136 }
137
138 fn has_empty_strs(&self) -> bool {
139 self.strs.is_empty()
140 }
141}
142
143fn extract_index(s: &str) -> (String, Option<i64>) {
144 if let Some(start_idx) = s.rfind('[')
145 && start_idx > 0
146 && s.ends_with(']')
147 {
148 let index_str = &s[start_idx + 1..s.len() - 1];
149 if let Ok(index) = index_str.parse::<i64>() {
150 let name = s[..start_idx].to_string();
151 return (name, Some(index));
152 }
153 }
154 (s.to_string(), None)
155}
156
157#[local_impl::local_impl]
158impl VariableRefExt for VariableRef {
159 fn new(path: ScopeRef, name: String) -> Self {
160 Self::new_with_id_and_index(path, name, VarId::default(), None)
161 }
162
163 fn new_with_id_and_index(path: ScopeRef, name: String, id: VarId, index: Option<i64>) -> Self {
164 let (name, index) = if index.is_none() {
165 extract_index(&name)
166 } else {
167 (name, index)
168 };
169 Self {
170 path,
171 name,
172 id,
173 index,
174 }
175 }
176
177 fn from_hierarchy_string(s: &str) -> Self {
178 let components = s.split('.').map(ToString::to_string).collect::<Vec<_>>();
179
180 if components.is_empty() {
181 Self {
182 path: ScopeRef::empty(),
183 name: String::new(),
184 id: VarId::default(),
185 index: None,
186 }
187 } else {
188 let name = components.last().unwrap();
189 let (name, index) = extract_index(name);
190 Self {
191 path: ScopeRef::from_strs(&components[..(components.len()) - 1]),
192 name,
193 id: VarId::default(),
194 index,
195 }
196 }
197 }
198
199 fn from_hierarchy_string_with_id(s: &str, id: VarId) -> Self {
200 let components = s
201 .split('.')
202 .map(std::string::ToString::to_string)
203 .collect::<Vec<_>>();
204
205 if components.is_empty() {
206 Self {
207 path: ScopeRef::empty(),
208 name: String::new(),
209 id,
210 index: None,
211 }
212 } else {
213 Self {
214 path: ScopeRef::from_strs(&components[..(components.len()) - 1]),
215 name: components.last().unwrap().clone(),
216 id,
217 index: None,
218 }
219 }
220 }
221
222 fn full_path_string_no_index(&self) -> String {
224 if self.path.has_empty_strs() {
225 self.name.clone()
226 } else {
227 format!("{}.{}", self.path, self.name)
228 }
229 }
230
231 fn full_path_string(&self) -> String {
233 if let Some(index) = self.index {
234 format!("{}.{}[{}]", self.path, self.name, index)
235 } else {
236 self.full_path_string_no_index()
237 }
238 }
239
240 fn full_path(&self) -> Vec<String> {
242 self.path
243 .strs()
244 .iter()
245 .cloned()
246 .chain([self.name.clone()])
247 .collect()
248 }
249
250 fn full_path_with_index(&self) -> Vec<String> {
252 if let Some(index) = self.index {
253 self.path
254 .strs()
255 .iter()
256 .cloned()
257 .chain([self.name.clone(), format!("[{index}]")])
258 .collect()
259 } else {
260 self.full_path()
261 }
262 }
263
264 fn from_strs(s: &[&str]) -> Self {
265 Self {
266 path: ScopeRef::from_strs(&s[..(s.len() - 1)]),
267 name: (*s.last().expect("from_strs called with an empty string")).to_string(),
268 id: VarId::default(),
269 index: None,
270 }
271 }
272
273 fn clear_id(&mut self) {
274 self.id = VarId::default();
275 }
276
277 fn cxxrtl_repr(&self) -> String {
278 self.full_path().join(" ")
279 }
280}
281
282#[local_impl::local_impl]
283impl FieldRefExt for FieldRef {
284 fn without_fields(root: VariableRef) -> Self {
285 Self {
286 root,
287 field: vec![],
288 }
289 }
290
291 fn from_strs(root: &[&str], field: &[&str]) -> Self {
292 Self {
293 root: VariableRef::from_strs(root),
294 field: field.iter().map(ToString::to_string).collect(),
295 }
296 }
297}
298
299pub enum WaveContainer {
300 Wellen(Box<WellenContainer>),
301 Empty,
306 Cxxrtl(Box<Mutex<CxxrtlContainer>>),
307}
308
309impl WaveContainer {
310 #[must_use]
311 pub fn new_waveform(hierarchy: std::sync::Arc<wellen::Hierarchy>) -> Self {
312 WaveContainer::Wellen(Box::new(WellenContainer::new(hierarchy, None, None)))
313 }
314
315 #[must_use]
316 pub fn new_remote_waveform(
317 server_url: &str,
318 hierarchy: std::sync::Arc<wellen::Hierarchy>,
319 file_index: usize,
320 ) -> Self {
321 WaveContainer::Wellen(Box::new(WellenContainer::new(
322 hierarchy,
323 Some(server_url.to_string()),
324 Some(file_index),
325 )))
326 }
327
328 #[must_use]
333 pub fn __new_empty() -> Self {
334 WaveContainer::Empty
335 }
336
337 pub fn tick(&self) {
339 match self {
340 WaveContainer::Wellen(_) => {}
341 WaveContainer::Empty => {}
342 WaveContainer::Cxxrtl(c) => c.lock().unwrap().tick(),
343 }
344 }
345
346 #[must_use]
347 pub fn wants_anti_aliasing(&self) -> bool {
348 match self {
349 WaveContainer::Wellen(_) => true,
350 WaveContainer::Empty => true,
351 WaveContainer::Cxxrtl(_) => true,
353 }
354 }
355
356 #[must_use]
360 pub fn is_fully_loaded(&self) -> bool {
361 match self {
362 WaveContainer::Wellen(f) => f.is_fully_loaded(),
363 WaveContainer::Empty => true,
364 WaveContainer::Cxxrtl(_) => true,
365 }
366 }
367
368 #[must_use]
370 pub fn variable_names(&self) -> Vec<String> {
371 match self {
372 WaveContainer::Wellen(f) => f.variable_names(),
373 WaveContainer::Empty => vec![],
374 WaveContainer::Cxxrtl(_) => vec![], }
377 }
378
379 #[must_use]
381 pub fn variables(&self) -> Vec<VariableRef> {
382 match self {
383 WaveContainer::Wellen(f) => f.variables(),
384 WaveContainer::Empty => vec![],
385 WaveContainer::Cxxrtl(_) => vec![],
386 }
387 }
388
389 #[must_use]
391 pub fn variables_in_scope(&self, scope: &ScopeRef) -> Vec<VariableRef> {
392 match self {
393 WaveContainer::Wellen(f) => f.variables_in_scope(scope),
394 WaveContainer::Empty => vec![],
395 WaveContainer::Cxxrtl(c) => c.lock().unwrap().variables_in_module(scope),
396 }
397 }
398
399 #[must_use]
401 pub fn parameters_in_scope(&self, scope: &ScopeRef) -> Vec<VariableRef> {
402 match self {
403 WaveContainer::Wellen(f) => f.parameters_in_scope(scope),
404 WaveContainer::Empty => vec![],
405 WaveContainer::Cxxrtl(_) => vec![],
407 }
408 }
409
410 #[must_use]
412 pub fn no_variables_in_scope(&self, scope: &ScopeRef) -> bool {
413 match self {
414 WaveContainer::Wellen(f) => f.no_variables_in_scope(scope),
415 WaveContainer::Empty => true,
416 WaveContainer::Cxxrtl(c) => c.lock().unwrap().no_variables_in_module(scope),
417 }
418 }
419
420 pub fn load_variables<S: AsRef<VariableRef>, T: Iterator<Item = S>>(
424 &mut self,
425 variables: T,
426 ) -> Result<Option<LoadSignalsCmd>> {
427 match self {
428 WaveContainer::Wellen(f) => f.load_variables(variables),
429 WaveContainer::Empty => {
430 bail!("Cannot load variables from empty container.");
431 }
432 WaveContainer::Cxxrtl(c) => {
433 c.get_mut().unwrap().load_variables(variables);
434 Ok(None)
435 }
436 }
437 }
438 pub fn load_parameters(&mut self) -> Result<Option<LoadSignalsCmd>> {
440 match self {
441 WaveContainer::Wellen(f) => f.load_all_params(),
442 WaveContainer::Empty => {
443 bail!("Cannot load parameters from empty container.");
444 }
445 WaveContainer::Cxxrtl(_) => {
446 Ok(None)
448 }
449 }
450 }
451
452 pub fn on_signals_loaded(&mut self, res: LoadSignalsResult) -> Result<Option<LoadSignalsCmd>> {
457 match self {
458 WaveContainer::Wellen(f) => f.on_signals_loaded(res),
459 WaveContainer::Empty => {
460 bail!("on_load_signals should only be called with the wellen backend.");
461 }
462 WaveContainer::Cxxrtl(_) => {
463 bail!("on_load_signals should only be called with the wellen backend.");
464 }
465 }
466 }
467
468 pub fn variable_meta<'a>(&'a self, variable: &'a VariableRef) -> Result<VariableMeta> {
469 match self {
470 WaveContainer::Wellen(f) => f.variable_to_meta(variable),
471 WaveContainer::Empty => {
472 bail!("Getting meta from empty wave container");
473 }
474 WaveContainer::Cxxrtl(c) => c.lock().unwrap().variable_meta(variable),
475 }
476 }
477
478 pub fn query_variable(
482 &self,
483 variable: &VariableRef,
484 time: &BigUint,
485 ) -> Result<Option<QueryResult>> {
486 match self {
487 WaveContainer::Wellen(f) => f.query_variable(variable, time),
488 WaveContainer::Empty => {
489 bail!("Querying variable from empty wave container");
490 }
491 WaveContainer::Cxxrtl(c) => Ok(c.lock().unwrap().query_variable(variable, time)),
492 }
493 }
494
495 pub fn signal_accessor(&self, signal_id: SignalId) -> Result<SignalAccessor> {
496 match (self, signal_id) {
497 (WaveContainer::Wellen(f), SignalId::Wellen(signal_ref)) => {
498 Ok(SignalAccessor::Wellen(f.signal_accessor(signal_ref)?))
499 }
500 _ => {
501 bail!("Invalid signal accessor combination");
502 }
503 }
504 }
505 pub fn signal_id(&self, variable: &VariableRef) -> Result<SignalId> {
507 match self {
508 WaveContainer::Wellen(f) => Ok(SignalId::Wellen(f.signal_ref(variable)?)),
509 WaveContainer::Empty => {
510 bail!("No signal data");
511 }
512 WaveContainer::Cxxrtl(_) => {
513 bail!("Not supported for Cxxrtl yet");
514 }
515 }
516 }
517
518 #[must_use]
520 pub fn is_signal_loaded(&self, signal_id: &SignalId) -> bool {
521 match (self, signal_id) {
522 (WaveContainer::Wellen(f), SignalId::Wellen(signal_ref)) => {
523 f.is_signal_loaded(*signal_ref)
524 }
525 _ => false,
526 }
527 }
528
529 #[cfg(not(target_arch = "wasm32"))]
530 pub(crate) fn prepare_fst_export(&self, variables: &[VariableRef]) -> Result<FstExport> {
533 match self {
534 WaveContainer::Wellen(f) => Ok(FstExport::Wellen(f.prepare_fst_export(variables)?)),
535 WaveContainer::Empty => {
536 bail!("No waveform data to export");
537 }
538 WaveContainer::Cxxrtl(_) => {
539 bail!("Exporting to FST is not supported for Cxxrtl");
540 }
541 }
542 }
543
544 #[must_use]
546 pub fn update_variable_ref(&self, variable: &VariableRef) -> Option<VariableRef> {
547 match self {
548 WaveContainer::Wellen(f) => f.update_variable_ref(variable),
549 WaveContainer::Empty => None,
550 WaveContainer::Cxxrtl(_) => None,
551 }
552 }
553
554 #[must_use]
556 pub fn scope_names(&self) -> Vec<String> {
557 match self {
558 WaveContainer::Wellen(f) => f.scope_names(),
559 WaveContainer::Empty => vec![],
560 WaveContainer::Cxxrtl(c) => c
561 .lock()
562 .unwrap()
563 .modules()
564 .iter()
565 .map(|m| m.strs().last().cloned().unwrap_or("root".to_string()))
566 .collect(),
567 }
568 }
569
570 #[must_use]
572 pub fn array_names(&self) -> Vec<String> {
573 match self {
574 WaveContainer::Wellen(f) => f.array_scope_names(),
575 WaveContainer::Empty => vec![],
576 WaveContainer::Cxxrtl(_) => vec![],
577 }
578 }
579
580 #[must_use]
581 pub fn metadata(&self) -> MetaData {
582 match self {
583 WaveContainer::Wellen(f) => f.metadata(),
584 WaveContainer::Empty => MetaData {
585 date: None,
586 version: None,
587 timescale: TimeScale {
588 unit: TimeUnit::None,
589 multiplier: None,
590 },
591 },
592 WaveContainer::Cxxrtl(_) => {
593 MetaData {
594 date: None,
595 version: None,
596 timescale: TimeScale {
597 unit: TimeUnit::FemtoSeconds,
599 multiplier: None,
600 },
601 }
602 }
603 }
604 }
605
606 #[must_use]
607 pub fn root_scopes(&self) -> Vec<ScopeRef> {
608 match self {
609 WaveContainer::Wellen(f) => f.root_scopes(),
610 WaveContainer::Empty => vec![],
611 WaveContainer::Cxxrtl(c) => c.lock().unwrap().root_modules(),
612 }
613 }
614
615 pub fn child_scopes(&self, scope: &ScopeRef) -> Result<Vec<ScopeRef>> {
616 match self {
617 WaveContainer::Wellen(f) => f.child_scopes(scope),
618 WaveContainer::Empty => {
619 bail!("Getting child modules from empty wave container");
620 }
621 WaveContainer::Cxxrtl(c) => Ok(c.lock().unwrap().child_scopes(scope)),
622 }
623 }
624
625 #[must_use]
626 pub fn max_timestamp(&self) -> Option<BigUint> {
627 match self {
628 WaveContainer::Wellen(f) => f.max_timestamp(),
629 WaveContainer::Empty => None,
630 WaveContainer::Cxxrtl(c) => c
631 .lock()
632 .unwrap()
633 .max_displayed_timestamp()
634 .map(|t| t.as_femtoseconds()),
635 }
636 }
637 #[must_use]
638 pub fn min_timestamp(&self) -> Option<BigUint> {
639 match self {
640 WaveContainer::Wellen(f) => f.min_timestamp(),
641 WaveContainer::Empty => None,
642 WaveContainer::Cxxrtl(_) => None,
643 }
644 }
645
646 #[must_use]
647 pub fn scope_exists(&self, scope: &ScopeRef) -> bool {
648 match self {
649 WaveContainer::Wellen(f) => f.scope_exists(scope),
650 WaveContainer::Empty => false,
651 WaveContainer::Cxxrtl(c) => c.lock().unwrap().module_exists(scope),
652 }
653 }
654
655 #[must_use]
656 pub fn scope_is_variable(&self, scope: &ScopeRef) -> bool {
658 match self {
659 WaveContainer::Wellen(f) => f.scope_is_variable(scope),
660 WaveContainer::Empty => false,
661 WaveContainer::Cxxrtl(_) => false, }
663 }
664
665 #[must_use]
666 pub fn scope_is_array(&self, scope: &ScopeRef) -> bool {
668 match self {
669 WaveContainer::Wellen(f) => f.scope_is_array(scope),
670 WaveContainer::Empty => false,
671 WaveContainer::Cxxrtl(_) => false, }
673 }
674
675 #[must_use]
678 pub fn get_scope_tooltip_data(&self, scope: &ScopeRef) -> String {
679 match self {
680 WaveContainer::Wellen(f) => f.get_scope_tooltip_data(scope),
681 WaveContainer::Empty => String::new(),
682 WaveContainer::Cxxrtl(_) => String::new(),
684 }
685 }
686
687 #[must_use]
690 pub fn get_scope_type(&self, scope: &ScopeRef) -> Option<wellen::ScopeType> {
691 match self {
692 WaveContainer::Wellen(f) => f.get_scope_type(scope),
693 WaveContainer::Empty | WaveContainer::Cxxrtl(_) => None,
694 }
695 }
696
697 #[must_use]
702 pub fn simulation_status(&self) -> Option<SimulationStatus> {
703 match self {
704 WaveContainer::Wellen(_) => None,
705 WaveContainer::Empty => None,
706 WaveContainer::Cxxrtl(c) => c.lock().unwrap().simulation_status(),
707 }
708 }
709
710 pub fn unpause_simulation(&self) {
713 match self {
714 WaveContainer::Wellen(_) => {}
715 WaveContainer::Empty => {}
716 WaveContainer::Cxxrtl(c) => c.lock().unwrap().unpause(),
717 }
718 }
719
720 pub fn pause_simulation(&self) {
722 match self {
723 WaveContainer::Wellen(_) => {}
724 WaveContainer::Empty => {}
725 WaveContainer::Cxxrtl(c) => c.lock().unwrap().pause(),
726 }
727 }
728
729 pub fn wellen_add_body(&mut self, body: BodyResult) -> Result<Option<LoadSignalsCmd>> {
731 match self {
732 WaveContainer::Wellen(inner) => inner.add_body(body),
733 _ => {
734 bail!("Should never call this function on a non wellen container!");
735 }
736 }
737 }
738
739 #[must_use]
740 pub fn body_loaded(&self) -> bool {
741 match self {
742 WaveContainer::Wellen(inner) => inner.body_loaded(),
743 WaveContainer::Empty => true,
744 WaveContainer::Cxxrtl(_) => true,
745 }
746 }
747
748 #[must_use]
751 pub fn supports_analog(&self) -> bool {
752 matches!(self, WaveContainer::Wellen(_))
753 }
754}
755
756#[cfg(test)]
757mod tests {
758 use super::*;
759
760 #[test]
761 fn extract_index_with_valid_index() {
762 let (name, index) = extract_index("signal[5]");
763 assert_eq!(name, "signal");
764 assert_eq!(index, Some(5));
765 }
766
767 #[test]
768 fn extract_index_with_zero_index() {
769 let (name, index) = extract_index("data[0]");
770 assert_eq!(name, "data");
771 assert_eq!(index, Some(0));
772 }
773
774 #[test]
775 fn extract_index_with_negative_index() {
776 let (name, index) = extract_index("array[-1]");
777 assert_eq!(name, "array");
778 assert_eq!(index, Some(-1));
779 }
780
781 #[test]
782 fn extract_index_with_large_number() {
783 let (name, index) = extract_index("mem[999999]");
784 assert_eq!(name, "mem");
785 assert_eq!(index, Some(999999));
786 }
787
788 #[test]
789 fn extract_index_no_brackets() {
790 let (name, index) = extract_index("simple_signal");
791 assert_eq!(name, "simple_signal");
792 assert_eq!(index, None);
793 }
794
795 #[test]
796 fn extract_index_empty_brackets() {
797 let (name, index) = extract_index("signal[]");
798 assert_eq!(name, "signal[]");
799 assert_eq!(index, None);
800 }
801
802 #[test]
803 fn extract_index_non_numeric_index() {
804 let (name, index) = extract_index("signal[abc]");
805 assert_eq!(name, "signal[abc]");
806 assert_eq!(index, None);
807 }
808
809 #[test]
810 fn extract_index_only_opening_bracket() {
811 let (name, index) = extract_index("signal[5");
812 assert_eq!(name, "signal[5");
813 assert_eq!(index, None);
814 }
815
816 #[test]
817 fn extract_index_only_closing_bracket() {
818 let (name, index) = extract_index("signal5]");
819 assert_eq!(name, "signal5]");
820 assert_eq!(index, None);
821 }
822
823 #[test]
824 fn extract_index_multiple_brackets() {
825 let (name, index) = extract_index("array[3][5]");
826 assert_eq!(name, "array[3]");
827 assert_eq!(index, Some(5));
828 }
829
830 #[test]
831 fn extract_index_with_dot_notation() {
832 let (name, index) = extract_index("struct.field[10]");
833 assert_eq!(name, "struct.field");
834 assert_eq!(index, Some(10));
835 }
836
837 #[test]
838 fn extract_index_bracket_at_start() {
839 let (name, index) = extract_index("[5]signal");
840 assert_eq!(name, "[5]signal");
841 assert_eq!(index, None);
842 }
843
844 #[test]
845 fn extract_index_no_text() {
846 let (name, index) = extract_index("[5]");
847 assert_eq!(name, "[5]");
848 assert_eq!(index, None);
849 }
850}