libsurfer/
variable_name_type.rs

1use derive_more::Display;
2use enum_iterator::Sequence;
3use itertools::Itertools;
4use std::str::FromStr;
5
6use serde::{Deserialize, Serialize};
7
8use crate::displayed_item_tree::Node;
9use crate::wave_container::{ScopeRefExt, VariableRefExt};
10use crate::{displayed_item::DisplayedItem, wave_container::VariableRef, wave_data::WaveData};
11
12#[derive(PartialEq, Copy, Clone, Debug, Deserialize, Display, Serialize, Sequence)]
13pub enum VariableNameType {
14    /// Local variable name only (i.e. for tb.dut.clk => clk)
15    #[display("Local")]
16    Local,
17
18    /// Add unique prefix, prefix + local
19    #[display("Unique")]
20    Unique,
21
22    /// Full variable name (i.e. tb.dut.clk => tb.dut.clk)
23    #[display("Global")]
24    Global,
25}
26
27impl FromStr for VariableNameType {
28    type Err = String;
29
30    fn from_str(input: &str) -> Result<VariableNameType, Self::Err> {
31        match input {
32            "Local" => Ok(VariableNameType::Local),
33            "Unique" => Ok(VariableNameType::Unique),
34            "Global" => Ok(VariableNameType::Global),
35            _ => Err(format!(
36                "'{input}' is not a valid VariableNameType (Valid options: Local|Unique|Global)"
37            )),
38        }
39    }
40}
41
42impl WaveData {
43    pub fn compute_variable_display_names(&mut self) {
44        let full_names = self
45            .items_tree
46            .iter()
47            .map(|node| self.displayed_items.get(&node.item_ref))
48            .filter_map(|item| match item {
49                Some(DisplayedItem::Variable(variable)) => Some(variable.variable_ref.clone()),
50                _ => None,
51            })
52            .unique()
53            .collect_vec();
54
55        for Node { item_ref, .. } in self.items_tree.iter() {
56            self.displayed_items
57                .entry(*item_ref)
58                .and_modify(|item| match item {
59                    DisplayedItem::Variable(variable) => {
60                        let local_name = variable.variable_ref.name.clone();
61                        variable.display_name = match variable.display_name_type {
62                            VariableNameType::Local => local_name,
63                            VariableNameType::Global => variable.variable_ref.full_path_string(),
64                            VariableNameType::Unique => {
65                                /// This function takes a full variable name and a list of other
66                                /// full variable names and returns a minimal unique variable name.
67                                /// It takes scopes from the back of the variable until the name is unique.
68                                fn unique(
69                                    variable: &VariableRef,
70                                    variables: &[VariableRef],
71                                ) -> String {
72                                    let other_variables = variables
73                                        .iter()
74                                        .filter(|&s| {
75                                            *s.full_path_string() != variable.full_path_string()
76                                        })
77                                        .collect_vec();
78
79                                    fn take_front(v: &VariableRef, l: usize) -> String {
80                                        if l == 0 {
81                                            v.name.clone()
82                                        } else {
83                                            format!(
84                                                "{}{}.{}",
85                                                if l < v.path.strs().len() { "…" } else { "" },
86                                                v.path.strs().iter().rev().take(l).rev().join("."),
87                                                v.name
88                                            )
89                                        }
90                                    }
91
92                                    let mut l = 0;
93                                    while other_variables
94                                        .iter()
95                                        .map(|v| take_front(v, l))
96                                        .contains(&take_front(variable, l))
97                                    {
98                                        l += 1;
99                                    }
100                                    take_front(variable, l)
101                                }
102
103                                unique(&variable.variable_ref, &full_names)
104                            }
105                        };
106                        if self.display_variable_indices {
107                            let index = self
108                                .inner
109                                .as_waves()
110                                .unwrap()
111                                .variable_meta(&variable.variable_ref)
112                                .ok()
113                                .as_ref()
114                                .and_then(|meta| meta.index)
115                                .map(|index| format!(" {index}"))
116                                .unwrap_or_default();
117                            variable.display_name = format!("{}{}", variable.display_name, index);
118                        }
119                    }
120                    DisplayedItem::Divider(_) => {}
121                    DisplayedItem::Marker(_) => {}
122                    DisplayedItem::TimeLine(_) => {}
123                    DisplayedItem::Placeholder(_) => {}
124                    DisplayedItem::Stream(_) => {}
125                    DisplayedItem::Group(_) => {}
126                });
127        }
128    }
129
130    pub fn force_variable_name_type(&mut self, name_type: VariableNameType) {
131        for Node { item_ref, .. } in self.items_tree.iter() {
132            self.displayed_items.entry(*item_ref).and_modify(|item| {
133                if let DisplayedItem::Variable(variable) = item {
134                    variable.display_name_type = name_type;
135                }
136            });
137        }
138        self.default_variable_name_type = name_type;
139        self.compute_variable_display_names();
140    }
141}