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().to_string();
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().to_string(),
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)))
310 }
311
312 #[must_use]
313 pub fn new_remote_waveform(
314 server_url: &str,
315 hierarchy: std::sync::Arc<wellen::Hierarchy>,
316 ) -> Self {
317 WaveContainer::Wellen(Box::new(WellenContainer::new(
318 hierarchy,
319 Some(server_url.to_string()),
320 )))
321 }
322
323 #[must_use]
327 pub fn __new_empty() -> Self {
328 WaveContainer::Empty
329 }
330
331 pub fn tick(&self) {
333 match self {
334 WaveContainer::Wellen(_) => {}
335 WaveContainer::Empty => {}
336 WaveContainer::Cxxrtl(c) => c.lock().unwrap().tick(),
337 }
338 }
339
340 #[must_use]
341 pub fn wants_anti_aliasing(&self) -> bool {
342 match self {
343 WaveContainer::Wellen(_) => true,
344 WaveContainer::Empty => true,
345 WaveContainer::Cxxrtl(_) => true,
347 }
348 }
349
350 #[must_use]
354 pub fn is_fully_loaded(&self) -> bool {
355 match self {
356 WaveContainer::Wellen(f) => f.is_fully_loaded(),
357 WaveContainer::Empty => true,
358 WaveContainer::Cxxrtl(_) => true,
359 }
360 }
361
362 #[must_use]
364 pub fn variable_names(&self) -> Vec<String> {
365 match self {
366 WaveContainer::Wellen(f) => f.variable_names(),
367 WaveContainer::Empty => vec![],
368 WaveContainer::Cxxrtl(_) => vec![], }
371 }
372
373 #[must_use]
375 pub fn variables(&self) -> Vec<VariableRef> {
376 match self {
377 WaveContainer::Wellen(f) => f.variables(),
378 WaveContainer::Empty => vec![],
379 WaveContainer::Cxxrtl(_) => vec![],
380 }
381 }
382
383 #[must_use]
385 pub fn variables_in_scope(&self, scope: &ScopeRef) -> Vec<VariableRef> {
386 match self {
387 WaveContainer::Wellen(f) => f.variables_in_scope(scope),
388 WaveContainer::Empty => vec![],
389 WaveContainer::Cxxrtl(c) => c.lock().unwrap().variables_in_module(scope),
390 }
391 }
392
393 #[must_use]
395 pub fn parameters_in_scope(&self, scope: &ScopeRef) -> Vec<VariableRef> {
396 match self {
397 WaveContainer::Wellen(f) => f.parameters_in_scope(scope),
398 WaveContainer::Empty => vec![],
399 WaveContainer::Cxxrtl(_) => vec![],
401 }
402 }
403
404 #[must_use]
406 pub fn no_variables_in_scope(&self, scope: &ScopeRef) -> bool {
407 match self {
408 WaveContainer::Wellen(f) => f.no_variables_in_scope(scope),
409 WaveContainer::Empty => true,
410 WaveContainer::Cxxrtl(c) => c.lock().unwrap().no_variables_in_module(scope),
411 }
412 }
413
414 pub fn load_variables<S: AsRef<VariableRef>, T: Iterator<Item = S>>(
416 &mut self,
417 variables: T,
418 ) -> Result<Option<LoadSignalsCmd>> {
419 match self {
420 WaveContainer::Wellen(f) => f.load_variables(variables),
421 WaveContainer::Empty => bail!("Cannot load variables from empty container."),
422 WaveContainer::Cxxrtl(c) => {
423 c.get_mut().unwrap().load_variables(variables);
424 Ok(None)
425 }
426 }
427 }
428 pub fn load_parameters(&mut self) -> Result<Option<LoadSignalsCmd>> {
430 match self {
431 WaveContainer::Wellen(f) => f.load_all_params(),
432 WaveContainer::Empty => bail!("Cannot load parameters from empty container."),
433 WaveContainer::Cxxrtl(_) => {
434 Ok(None)
436 }
437 }
438 }
439
440 pub fn on_signals_loaded(&mut self, res: LoadSignalsResult) -> Result<Option<LoadSignalsCmd>> {
443 match self {
444 WaveContainer::Wellen(f) => f.on_signals_loaded(res),
445 WaveContainer::Empty => {
446 bail!("on_load_signals should only be called with the wellen backend.")
447 }
448 WaveContainer::Cxxrtl(_) => {
449 bail!("on_load_signals should only be called with the wellen backend.")
450 }
451 }
452 }
453
454 pub fn variable_meta<'a>(&'a self, variable: &'a VariableRef) -> Result<VariableMeta> {
455 match self {
456 WaveContainer::Wellen(f) => f.variable_to_meta(variable),
457 WaveContainer::Empty => bail!("Getting meta from empty wave container"),
458 WaveContainer::Cxxrtl(c) => c.lock().unwrap().variable_meta(variable),
459 }
460 }
461
462 pub fn query_variable(
466 &self,
467 variable: &VariableRef,
468 time: &BigUint,
469 ) -> Result<Option<QueryResult>> {
470 match self {
471 WaveContainer::Wellen(f) => f.query_variable(variable, time),
472 WaveContainer::Empty => bail!("Querying variable from empty wave container"),
473 WaveContainer::Cxxrtl(c) => Ok(c.lock().unwrap().query_variable(variable, time)),
474 }
475 }
476
477 pub fn signal_accessor(&self, signal_id: SignalId) -> Result<SignalAccessor> {
478 match (self, signal_id) {
479 (WaveContainer::Wellen(f), SignalId::Wellen(signal_ref)) => {
480 Ok(SignalAccessor::Wellen(f.signal_accessor(signal_ref)?))
481 }
482 _ => bail!("Invalid signal accessor combination"),
483 }
484 }
485 pub fn signal_id(&self, variable: &VariableRef) -> Result<SignalId> {
487 match self {
488 WaveContainer::Wellen(f) => Ok(SignalId::Wellen(f.signal_ref(variable)?)),
489 WaveContainer::Empty => bail!("No signal data"),
490 WaveContainer::Cxxrtl(_) => bail!("Not supported for Cxxrtl yet"),
491 }
492 }
493
494 #[must_use]
496 pub fn is_signal_loaded(&self, signal_id: &SignalId) -> bool {
497 match (self, signal_id) {
498 (WaveContainer::Wellen(f), SignalId::Wellen(signal_ref)) => {
499 f.is_signal_loaded(*signal_ref)
500 }
501 _ => false,
502 }
503 }
504
505 #[must_use]
507 pub fn update_variable_ref(&self, variable: &VariableRef) -> Option<VariableRef> {
508 match self {
509 WaveContainer::Wellen(f) => f.update_variable_ref(variable),
510 WaveContainer::Empty => None,
511 WaveContainer::Cxxrtl(_) => None,
512 }
513 }
514
515 #[must_use]
517 pub fn scope_names(&self) -> Vec<String> {
518 match self {
519 WaveContainer::Wellen(f) => f.scope_names(),
520 WaveContainer::Empty => vec![],
521 WaveContainer::Cxxrtl(c) => c
522 .lock()
523 .unwrap()
524 .modules()
525 .iter()
526 .map(|m| m.strs().last().cloned().unwrap_or("root".to_string()))
527 .collect(),
528 }
529 }
530
531 #[must_use]
533 pub fn array_names(&self) -> Vec<String> {
534 match self {
535 WaveContainer::Wellen(f) => f.array_scope_names(),
536 WaveContainer::Empty => vec![],
537 WaveContainer::Cxxrtl(_) => vec![],
538 }
539 }
540
541 #[must_use]
542 pub fn metadata(&self) -> MetaData {
543 match self {
544 WaveContainer::Wellen(f) => f.metadata(),
545 WaveContainer::Empty => MetaData {
546 date: None,
547 version: None,
548 timescale: TimeScale {
549 unit: TimeUnit::None,
550 multiplier: None,
551 },
552 },
553 WaveContainer::Cxxrtl(_) => {
554 MetaData {
555 date: None,
556 version: None,
557 timescale: TimeScale {
558 unit: TimeUnit::FemtoSeconds,
560 multiplier: None,
561 },
562 }
563 }
564 }
565 }
566
567 #[must_use]
568 pub fn root_scopes(&self) -> Vec<ScopeRef> {
569 match self {
570 WaveContainer::Wellen(f) => f.root_scopes(),
571 WaveContainer::Empty => vec![],
572 WaveContainer::Cxxrtl(c) => c.lock().unwrap().root_modules(),
573 }
574 }
575
576 pub fn child_scopes(&self, scope: &ScopeRef) -> Result<Vec<ScopeRef>> {
577 match self {
578 WaveContainer::Wellen(f) => f.child_scopes(scope),
579 WaveContainer::Empty => bail!("Getting child modules from empty wave container"),
580 WaveContainer::Cxxrtl(c) => Ok(c.lock().unwrap().child_scopes(scope)),
581 }
582 }
583
584 #[must_use]
585 pub fn max_timestamp(&self) -> Option<BigUint> {
586 match self {
587 WaveContainer::Wellen(f) => f.max_timestamp(),
588 WaveContainer::Empty => None,
589 WaveContainer::Cxxrtl(c) => c
590 .lock()
591 .unwrap()
592 .max_displayed_timestamp()
593 .map(|t| t.as_femtoseconds()),
594 }
595 }
596
597 #[must_use]
598 pub fn scope_exists(&self, scope: &ScopeRef) -> bool {
599 match self {
600 WaveContainer::Wellen(f) => f.scope_exists(scope),
601 WaveContainer::Empty => false,
602 WaveContainer::Cxxrtl(c) => c.lock().unwrap().module_exists(scope),
603 }
604 }
605
606 #[must_use]
607 pub fn scope_is_variable(&self, scope: &ScopeRef) -> bool {
609 match self {
610 WaveContainer::Wellen(f) => f.scope_is_variable(scope),
611 WaveContainer::Empty => false,
612 WaveContainer::Cxxrtl(_) => false, }
614 }
615
616 #[must_use]
617 pub fn scope_is_array(&self, scope: &ScopeRef) -> bool {
619 match self {
620 WaveContainer::Wellen(f) => f.scope_is_array(scope),
621 WaveContainer::Empty => false,
622 WaveContainer::Cxxrtl(_) => false, }
624 }
625
626 #[must_use]
629 pub fn get_scope_tooltip_data(&self, scope: &ScopeRef) -> String {
630 match self {
631 WaveContainer::Wellen(f) => f.get_scope_tooltip_data(scope),
632 WaveContainer::Empty => String::new(),
633 WaveContainer::Cxxrtl(_) => String::new(),
635 }
636 }
637
638 #[must_use]
641 pub fn get_scope_type(&self, scope: &ScopeRef) -> Option<wellen::ScopeType> {
642 match self {
643 WaveContainer::Wellen(f) => f.get_scope_type(scope),
644 WaveContainer::Empty | WaveContainer::Cxxrtl(_) => None,
645 }
646 }
647
648 #[must_use]
652 pub fn simulation_status(&self) -> Option<SimulationStatus> {
653 match self {
654 WaveContainer::Wellen(_) => None,
655 WaveContainer::Empty => None,
656 WaveContainer::Cxxrtl(c) => c.lock().unwrap().simulation_status(),
657 }
658 }
659
660 pub fn unpause_simulation(&self) {
663 match self {
664 WaveContainer::Wellen(_) => {}
665 WaveContainer::Empty => {}
666 WaveContainer::Cxxrtl(c) => c.lock().unwrap().unpause(),
667 }
668 }
669
670 pub fn pause_simulation(&self) {
672 match self {
673 WaveContainer::Wellen(_) => {}
674 WaveContainer::Empty => {}
675 WaveContainer::Cxxrtl(c) => c.lock().unwrap().pause(),
676 }
677 }
678
679 pub fn wellen_add_body(&mut self, body: BodyResult) -> Result<Option<LoadSignalsCmd>> {
681 match self {
682 WaveContainer::Wellen(inner) => inner.add_body(body),
683 _ => {
684 bail!("Should never call this function on a non wellen container!")
685 }
686 }
687 }
688
689 #[must_use]
690 pub fn body_loaded(&self) -> bool {
691 match self {
692 WaveContainer::Wellen(inner) => inner.body_loaded(),
693 WaveContainer::Empty => true,
694 WaveContainer::Cxxrtl(_) => true,
695 }
696 }
697
698 #[must_use]
701 pub fn supports_analog(&self) -> bool {
702 matches!(self, WaveContainer::Wellen(_))
703 }
704}
705
706#[cfg(test)]
707mod tests {
708 use super::*;
709
710 #[test]
711 fn extract_index_with_valid_index() {
712 let (name, index) = extract_index("signal[5]".to_string());
713 assert_eq!(name, "signal");
714 assert_eq!(index, Some(5));
715 }
716
717 #[test]
718 fn extract_index_with_zero_index() {
719 let (name, index) = extract_index("data[0]".to_string());
720 assert_eq!(name, "data");
721 assert_eq!(index, Some(0));
722 }
723
724 #[test]
725 fn extract_index_with_negative_index() {
726 let (name, index) = extract_index("array[-1]".to_string());
727 assert_eq!(name, "array");
728 assert_eq!(index, Some(-1));
729 }
730
731 #[test]
732 fn extract_index_with_large_number() {
733 let (name, index) = extract_index("mem[999999]".to_string());
734 assert_eq!(name, "mem");
735 assert_eq!(index, Some(999999));
736 }
737
738 #[test]
739 fn extract_index_no_brackets() {
740 let (name, index) = extract_index("simple_signal".to_string());
741 assert_eq!(name, "simple_signal");
742 assert_eq!(index, None);
743 }
744
745 #[test]
746 fn extract_index_empty_brackets() {
747 let (name, index) = extract_index("signal[]".to_string());
748 assert_eq!(name, "signal[]");
749 assert_eq!(index, None);
750 }
751
752 #[test]
753 fn extract_index_non_numeric_index() {
754 let (name, index) = extract_index("signal[abc]".to_string());
755 assert_eq!(name, "signal[abc]");
756 assert_eq!(index, None);
757 }
758
759 #[test]
760 fn extract_index_only_opening_bracket() {
761 let (name, index) = extract_index("signal[5".to_string());
762 assert_eq!(name, "signal[5");
763 assert_eq!(index, None);
764 }
765
766 #[test]
767 fn extract_index_only_closing_bracket() {
768 let (name, index) = extract_index("signal5]".to_string());
769 assert_eq!(name, "signal5]");
770 assert_eq!(index, None);
771 }
772
773 #[test]
774 fn extract_index_multiple_brackets() {
775 let (name, index) = extract_index("array[3][5]".to_string());
776 assert_eq!(name, "array[3]");
777 assert_eq!(index, Some(5));
778 }
779
780 #[test]
781 fn extract_index_with_dot_notation() {
782 let (name, index) = extract_index("struct.field[10]".to_string());
783 assert_eq!(name, "struct.field");
784 assert_eq!(index, Some(10));
785 }
786
787 #[test]
788 fn extract_index_bracket_at_start() {
789 let (name, index) = extract_index("[5]signal".to_string());
790 assert_eq!(name, "[5]signal");
791 assert_eq!(index, None);
792 }
793
794 #[test]
795 fn extract_index_no_text() {
796 let (name, index) = extract_index("[5]".to_string());
797 assert_eq!(name, "[5]");
798 assert_eq!(index, None);
799 }
800}