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 strs(&self) -> &[String] {
120 &self.strs
121 }
122
123 fn with_id(&self, id: ScopeId) -> Self {
124 let mut out = self.clone();
125 out.id = id;
126 out
127 }
128
129 fn cxxrtl_repr(&self) -> String {
130 self.strs.join(" ")
131 }
132
133 fn has_empty_strs(&self) -> bool {
134 self.strs.is_empty()
135 }
136}
137
138#[local_impl::local_impl]
139impl VariableRefExt for VariableRef {
140 fn new(path: ScopeRef, name: String) -> Self {
141 Self::new_with_id(path, name, VarId::default())
142 }
143
144 fn new_with_id(path: ScopeRef, name: String, id: VarId) -> Self {
145 Self { path, name, id }
146 }
147
148 fn from_hierarchy_string(s: &str) -> Self {
149 let components = s.split('.').map(ToString::to_string).collect::<Vec<_>>();
150
151 if components.is_empty() {
152 Self {
153 path: ScopeRef::empty(),
154 name: String::new(),
155 id: VarId::default(),
156 }
157 } else {
158 Self {
159 path: ScopeRef::from_strs(&components[..(components.len()) - 1]),
160 name: components.last().unwrap().to_string(),
161 id: VarId::default(),
162 }
163 }
164 }
165
166 fn from_hierarchy_string_with_id(s: &str, id: VarId) -> Self {
167 let components = s
168 .split('.')
169 .map(std::string::ToString::to_string)
170 .collect::<Vec<_>>();
171
172 if components.is_empty() {
173 Self {
174 path: ScopeRef::empty(),
175 name: String::new(),
176 id,
177 }
178 } else {
179 Self {
180 path: ScopeRef::from_strs(&components[..(components.len()) - 1]),
181 name: components.last().unwrap().to_string(),
182 id,
183 }
184 }
185 }
186
187 fn full_path_string(&self) -> String {
189 if self.path.has_empty_strs() {
190 self.name.clone()
191 } else {
192 format!("{}.{}", self.path, self.name)
193 }
194 }
195
196 fn full_path(&self) -> Vec<String> {
197 self.path
198 .strs()
199 .iter()
200 .cloned()
201 .chain([self.name.clone()])
202 .collect()
203 }
204
205 fn from_strs(s: &[&str]) -> Self {
206 Self {
207 path: ScopeRef::from_strs(&s[..(s.len() - 1)]),
208 name: (*s.last().expect("from_strs called with an empty string")).to_string(),
209 id: VarId::default(),
210 }
211 }
212
213 fn clear_id(&mut self) {
214 self.id = VarId::default();
215 }
216
217 fn cxxrtl_repr(&self) -> String {
218 self.full_path().join(" ")
219 }
220}
221
222#[local_impl::local_impl]
223impl FieldRefExt for FieldRef {
224 fn without_fields(root: VariableRef) -> Self {
225 Self {
226 root,
227 field: vec![],
228 }
229 }
230
231 fn from_strs(root: &[&str], field: &[&str]) -> Self {
232 Self {
233 root: VariableRef::from_strs(root),
234 field: field.iter().map(ToString::to_string).collect(),
235 }
236 }
237}
238
239pub enum WaveContainer {
240 Wellen(Box<WellenContainer>),
241 Empty,
244 Cxxrtl(Box<Mutex<CxxrtlContainer>>),
245}
246
247impl WaveContainer {
248 #[must_use]
249 pub fn new_waveform(hierarchy: std::sync::Arc<wellen::Hierarchy>) -> Self {
250 WaveContainer::Wellen(Box::new(WellenContainer::new(hierarchy, None)))
251 }
252
253 #[must_use]
254 pub fn new_remote_waveform(
255 server_url: &str,
256 hierarchy: std::sync::Arc<wellen::Hierarchy>,
257 ) -> Self {
258 WaveContainer::Wellen(Box::new(WellenContainer::new(
259 hierarchy,
260 Some(server_url.to_string()),
261 )))
262 }
263
264 #[must_use]
268 pub fn __new_empty() -> Self {
269 WaveContainer::Empty
270 }
271
272 pub fn tick(&self) {
274 match self {
275 WaveContainer::Wellen(_) => {}
276 WaveContainer::Empty => {}
277 WaveContainer::Cxxrtl(c) => c.lock().unwrap().tick(),
278 }
279 }
280
281 #[must_use]
282 pub fn wants_anti_aliasing(&self) -> bool {
283 match self {
284 WaveContainer::Wellen(_) => true,
285 WaveContainer::Empty => true,
286 WaveContainer::Cxxrtl(_) => true,
288 }
289 }
290
291 #[must_use]
295 pub fn is_fully_loaded(&self) -> bool {
296 match self {
297 WaveContainer::Wellen(f) => f.is_fully_loaded(),
298 WaveContainer::Empty => true,
299 WaveContainer::Cxxrtl(_) => true,
300 }
301 }
302
303 #[must_use]
305 pub fn variable_names(&self) -> Vec<String> {
306 match self {
307 WaveContainer::Wellen(f) => f.variable_names(),
308 WaveContainer::Empty => vec![],
309 WaveContainer::Cxxrtl(_) => vec![], }
312 }
313
314 #[must_use]
316 pub fn variables(&self) -> Vec<VariableRef> {
317 match self {
318 WaveContainer::Wellen(f) => f.variables(),
319 WaveContainer::Empty => vec![],
320 WaveContainer::Cxxrtl(_) => vec![],
321 }
322 }
323
324 #[must_use]
326 pub fn variables_in_scope(&self, scope: &ScopeRef) -> Vec<VariableRef> {
327 match self {
328 WaveContainer::Wellen(f) => f.variables_in_scope(scope),
329 WaveContainer::Empty => vec![],
330 WaveContainer::Cxxrtl(c) => c.lock().unwrap().variables_in_module(scope),
331 }
332 }
333
334 #[must_use]
336 pub fn parameters_in_scope(&self, scope: &ScopeRef) -> Vec<VariableRef> {
337 match self {
338 WaveContainer::Wellen(f) => f.parameters_in_scope(scope),
339 WaveContainer::Empty => vec![],
340 WaveContainer::Cxxrtl(_) => vec![],
342 }
343 }
344
345 #[must_use]
347 pub fn no_variables_in_scope(&self, scope: &ScopeRef) -> bool {
348 match self {
349 WaveContainer::Wellen(f) => f.no_variables_in_scope(scope),
350 WaveContainer::Empty => true,
351 WaveContainer::Cxxrtl(c) => c.lock().unwrap().no_variables_in_module(scope),
352 }
353 }
354
355 pub fn load_variables<S: AsRef<VariableRef>, T: Iterator<Item = S>>(
357 &mut self,
358 variables: T,
359 ) -> Result<Option<LoadSignalsCmd>> {
360 match self {
361 WaveContainer::Wellen(f) => f.load_variables(variables),
362 WaveContainer::Empty => bail!("Cannot load variables from empty container."),
363 WaveContainer::Cxxrtl(c) => {
364 c.get_mut().unwrap().load_variables(variables);
365 Ok(None)
366 }
367 }
368 }
369 pub fn load_parameters(&mut self) -> Result<Option<LoadSignalsCmd>> {
371 match self {
372 WaveContainer::Wellen(f) => f.load_all_params(),
373 WaveContainer::Empty => bail!("Cannot load parameters from empty container."),
374 WaveContainer::Cxxrtl(_) => {
375 Ok(None)
377 }
378 }
379 }
380
381 pub fn on_signals_loaded(&mut self, res: LoadSignalsResult) -> Result<Option<LoadSignalsCmd>> {
384 match self {
385 WaveContainer::Wellen(f) => f.on_signals_loaded(res),
386 WaveContainer::Empty => {
387 bail!("on_load_signals should only be called with the wellen backend.")
388 }
389 WaveContainer::Cxxrtl(_) => {
390 bail!("on_load_signals should only be called with the wellen backend.")
391 }
392 }
393 }
394
395 pub fn variable_meta<'a>(&'a self, variable: &'a VariableRef) -> Result<VariableMeta> {
396 match self {
397 WaveContainer::Wellen(f) => f.variable_to_meta(variable),
398 WaveContainer::Empty => bail!("Getting meta from empty wave container"),
399 WaveContainer::Cxxrtl(c) => c.lock().unwrap().variable_meta(variable),
400 }
401 }
402
403 pub fn query_variable(
407 &self,
408 variable: &VariableRef,
409 time: &BigUint,
410 ) -> Result<Option<QueryResult>> {
411 match self {
412 WaveContainer::Wellen(f) => f.query_variable(variable, time),
413 WaveContainer::Empty => bail!("Querying variable from empty wave container"),
414 WaveContainer::Cxxrtl(c) => Ok(c.lock().unwrap().query_variable(variable, time)),
415 }
416 }
417
418 pub fn signal_accessor(&self, signal_id: SignalId) -> Result<SignalAccessor> {
419 match (self, signal_id) {
420 (WaveContainer::Wellen(f), SignalId::Wellen(signal_ref)) => {
421 Ok(SignalAccessor::Wellen(f.signal_accessor(signal_ref)?))
422 }
423 _ => bail!("Invalid signal accessor combination"),
424 }
425 }
426 pub fn signal_id(&self, variable: &VariableRef) -> Result<SignalId> {
428 match self {
429 WaveContainer::Wellen(f) => Ok(SignalId::Wellen(f.signal_ref(variable)?)),
430 WaveContainer::Empty => bail!("No signal data"),
431 WaveContainer::Cxxrtl(_) => bail!("Not supported for Cxxrtl yet"),
432 }
433 }
434
435 #[must_use]
437 pub fn is_signal_loaded(&self, signal_id: &SignalId) -> bool {
438 match (self, signal_id) {
439 (WaveContainer::Wellen(f), SignalId::Wellen(signal_ref)) => {
440 f.is_signal_loaded(*signal_ref)
441 }
442 _ => false,
443 }
444 }
445
446 #[must_use]
448 pub fn update_variable_ref(&self, variable: &VariableRef) -> Option<VariableRef> {
449 match self {
450 WaveContainer::Wellen(f) => f.update_variable_ref(variable),
451 WaveContainer::Empty => None,
452 WaveContainer::Cxxrtl(_) => None,
453 }
454 }
455
456 #[must_use]
458 pub fn scope_names(&self) -> Vec<String> {
459 match self {
460 WaveContainer::Wellen(f) => f.scope_names(),
461 WaveContainer::Empty => vec![],
462 WaveContainer::Cxxrtl(c) => c
463 .lock()
464 .unwrap()
465 .modules()
466 .iter()
467 .map(|m| m.strs().last().cloned().unwrap_or("root".to_string()))
468 .collect(),
469 }
470 }
471
472 #[must_use]
473 pub fn metadata(&self) -> MetaData {
474 match self {
475 WaveContainer::Wellen(f) => f.metadata(),
476 WaveContainer::Empty => MetaData {
477 date: None,
478 version: None,
479 timescale: TimeScale {
480 unit: TimeUnit::None,
481 multiplier: None,
482 },
483 },
484 WaveContainer::Cxxrtl(_) => {
485 MetaData {
486 date: None,
487 version: None,
488 timescale: TimeScale {
489 unit: TimeUnit::FemtoSeconds,
491 multiplier: None,
492 },
493 }
494 }
495 }
496 }
497
498 #[must_use]
499 pub fn root_scopes(&self) -> Vec<ScopeRef> {
500 match self {
501 WaveContainer::Wellen(f) => f.root_scopes(),
502 WaveContainer::Empty => vec![],
503 WaveContainer::Cxxrtl(c) => c.lock().unwrap().root_modules(),
504 }
505 }
506
507 pub fn child_scopes(&self, scope: &ScopeRef) -> Result<Vec<ScopeRef>> {
508 match self {
509 WaveContainer::Wellen(f) => f.child_scopes(scope),
510 WaveContainer::Empty => bail!("Getting child modules from empty wave container"),
511 WaveContainer::Cxxrtl(c) => Ok(c.lock().unwrap().child_scopes(scope)),
512 }
513 }
514
515 #[must_use]
516 pub fn max_timestamp(&self) -> Option<BigUint> {
517 match self {
518 WaveContainer::Wellen(f) => f.max_timestamp(),
519 WaveContainer::Empty => None,
520 WaveContainer::Cxxrtl(c) => c
521 .lock()
522 .unwrap()
523 .max_displayed_timestamp()
524 .map(|t| t.as_femtoseconds()),
525 }
526 }
527
528 #[must_use]
529 pub fn scope_exists(&self, scope: &ScopeRef) -> bool {
530 match self {
531 WaveContainer::Wellen(f) => f.scope_exists(scope),
532 WaveContainer::Empty => false,
533 WaveContainer::Cxxrtl(c) => c.lock().unwrap().module_exists(scope),
534 }
535 }
536
537 #[must_use]
538 pub fn scope_is_variable(&self, scope: &ScopeRef) -> bool {
540 match self {
541 WaveContainer::Wellen(f) => f.scope_is_variable(scope),
542 WaveContainer::Empty => false,
543 WaveContainer::Cxxrtl(_) => false, }
545 }
546
547 #[must_use]
550 pub fn get_scope_tooltip_data(&self, scope: &ScopeRef) -> String {
551 match self {
552 WaveContainer::Wellen(f) => f.get_scope_tooltip_data(scope),
553 WaveContainer::Empty => String::new(),
554 WaveContainer::Cxxrtl(_) => String::new(),
556 }
557 }
558
559 #[must_use]
562 pub fn get_scope_type(&self, scope: &ScopeRef) -> Option<wellen::ScopeType> {
563 match self {
564 WaveContainer::Wellen(f) => f.get_scope_type(scope),
565 WaveContainer::Empty | WaveContainer::Cxxrtl(_) => None,
566 }
567 }
568
569 #[must_use]
573 pub fn simulation_status(&self) -> Option<SimulationStatus> {
574 match self {
575 WaveContainer::Wellen(_) => None,
576 WaveContainer::Empty => None,
577 WaveContainer::Cxxrtl(c) => c.lock().unwrap().simulation_status(),
578 }
579 }
580
581 pub fn unpause_simulation(&self) {
584 match self {
585 WaveContainer::Wellen(_) => {}
586 WaveContainer::Empty => {}
587 WaveContainer::Cxxrtl(c) => c.lock().unwrap().unpause(),
588 }
589 }
590
591 pub fn pause_simulation(&self) {
593 match self {
594 WaveContainer::Wellen(_) => {}
595 WaveContainer::Empty => {}
596 WaveContainer::Cxxrtl(c) => c.lock().unwrap().pause(),
597 }
598 }
599
600 pub fn wellen_add_body(&mut self, body: BodyResult) -> Result<Option<LoadSignalsCmd>> {
602 match self {
603 WaveContainer::Wellen(inner) => inner.add_body(body),
604 _ => {
605 bail!("Should never call this function on a non wellen container!")
606 }
607 }
608 }
609
610 #[must_use]
611 pub fn body_loaded(&self) -> bool {
612 match self {
613 WaveContainer::Wellen(inner) => inner.body_loaded(),
614 WaveContainer::Empty => true,
615 WaveContainer::Cxxrtl(_) => true,
616 }
617 }
618
619 #[must_use]
622 pub fn supports_analog(&self) -> bool {
623 matches!(self, WaveContainer::Wellen(_))
624 }
625}