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