Skip to main content

gwr_track/tracker/
aka.rs

1// Copyright (c) 2025 Graphcore Ltd. All rights reserved.
2
3//! Also Known As (AKA) - an alternative name manager.
4//!
5//! `Aka` lets a composite model expose stable public names while delegating the
6//! actual entity or port implementation to child components. Constructors named
7//! `new_and_register_with_renames` accept an `Option<&Aka>` and pass it to
8//! [`Entity::new_with_renames`](crate::entity::Entity::new_with_renames), port
9//! constructors such as `InPort::new_with_renames` and
10//! `OutPort::new_with_renames`, or child constructors so the tracking layer can
11//! record both the local implementation name and the parent-visible name.
12//!
13//! The usual public constructor should remain `new_and_register`; it normally
14//! calls the rename-aware constructor with `None` so users do not need to know
15//! about `Aka`. Add a rename-aware constructor when a component delegates
16//! public ports to internal subcomponents, composes other rename-aware
17//! children, or needs alternate names for tracking, filtering, or monitor
18//! configuration. Leaf components whose local ports are already their public
19//! API can stay with `new_and_register` until a real composition use case
20//! appears.
21
22use std::collections::HashMap;
23use std::fmt::Display;
24use std::rc::Rc;
25
26use crate::entity::Entity;
27
28/// Helper function for creating local Aka derived from incoming Aka
29#[macro_export]
30macro_rules! build_aka {
31    ($aka:ident, $parent:expr, $renames:expr) => {{
32        let mut tmp_aka = gwr_track::tracker::aka::Aka::default();
33        gwr_track::tracker::aka::populate_aka($aka, Some(&mut tmp_aka), $parent, $renames);
34        tmp_aka
35    }};
36}
37
38/// Type alias for the optional list of alternative names
39pub type AlternativeNames<'a> = Option<&'a Vec<String>>;
40
41/// A structure to manage alternative names for entities
42#[derive(Default)]
43pub struct Aka {
44    names: HashMap<String, Vec<String>>,
45}
46
47impl Aka {
48    /// Get the list of alternative names for an entity
49    #[must_use]
50    pub fn get_alternative_names<'a>(&'a self, name: &str) -> AlternativeNames<'a> {
51        self.names.get(name)
52    }
53}
54
55impl Display for Aka {
56    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57        write!(f, "{:#?}", self.names)
58    }
59}
60
61/// Lookup the renames for a given port name
62#[must_use]
63pub fn get_alternative_names<'a>(aka: Option<&'a Aka>, name: &str) -> AlternativeNames<'a> {
64    if let Some(aka) = aka {
65        return aka.get_alternative_names(name);
66    }
67    None
68}
69
70/// Build up a new set of alternative names with a new set of renames
71pub fn populate_aka_from_string(
72    aka: Option<&Aka>,
73    new_aka: Option<&mut Aka>,
74    entity: &Rc<Entity>,
75    renames: &[(String, String)],
76) {
77    let ref_names: Vec<(&str, &str)> = renames
78        .iter()
79        .map(|(a, b)| (a.as_str(), b.as_str()))
80        .collect();
81    populate_aka(aka, new_aka, entity, &ref_names);
82}
83
84/// Build up a new set of alternative names with a new set of renames.
85///
86/// Each tuple maps a name visible on `entity` to the child-local name that
87/// should inherit the alternative names. For example, a composite can map a
88/// public `rx_a` port to an internal limiter's `rx` port so traces and monitor
89/// configuration can refer to either level of the model.
90pub fn populate_aka(
91    aka: Option<&Aka>,
92    new_aka: Option<&mut Aka>,
93    entity: &Rc<Entity>,
94    renames: &[(&str, &str)],
95) {
96    if let Some(new_aka) = new_aka {
97        for (name_in_entity, name_in_child) in renames {
98            let renames = if let Some(aka) = aka.as_ref() {
99                match aka.names.get(*name_in_entity) {
100                    Some(existing_renames) => {
101                        let mut new_renames = existing_renames.clone();
102                        new_renames.push(format!("{}::{}", entity.full_name(), name_in_entity));
103                        new_renames
104                    }
105                    None => {
106                        vec![format!("{}::{}", entity.full_name(), name_in_entity)]
107                    }
108                }
109            } else {
110                vec![format!("{}::{}", entity.full_name(), name_in_entity)]
111            };
112            new_aka.names.insert((*name_in_child).to_string(), renames);
113        }
114    }
115}