Skip to main content

unlab_gpu/
mod_node.rs

1//
2// Copyright (c) 2025-2026 Ɓukasz Szpakowski
3//
4// This Source Code Form is subject to the terms of the Mozilla Public
5// License, v. 2.0. If a copy of the MPL was not distributed with this
6// file, You can obtain one at https://mozilla.org/MPL/2.0/.
7//
8//! A module of module node.
9use std::collections::HashMap;
10use std::sync::Arc;
11use std::sync::RwLock;
12use std::sync::Weak;
13use crate::error::*;
14use crate::utils::*;
15
16/// An enumeration of reference to module node.
17///
18/// The reference of module node can be a strong reference to module or a weak reference to
19/// module. If the reference of module node refers to ascestor, the reference of module node
20/// should be the weak reference because it is reference cycle.
21#[derive(Clone, Debug)]
22pub enum ModNodeRef<T, U>
23{
24    /// A strong reference to the module.
25    Arc(Arc<RwLock<ModNode<T, U>>>),
26    /// A weak refenece to the module.
27    Weak(Weak<RwLock<ModNode<T, U>>>),
28}
29
30impl<T, U> ModNodeRef<T, U>
31{
32    pub fn to_arc(&self) -> Option<Arc<RwLock<ModNode<T, U>>>>
33    {
34        match self {
35            ModNodeRef::Arc(arc) => Some(arc.clone()),
36            ModNodeRef::Weak(weak) => weak.upgrade(),
37        }
38    }
39}
40
41/// A structure of object of used variable.
42///
43/// The used variables available in a module, but are defined in other module. This object refers
44/// the used variable by the referecne to module node and the variable identifier.
45#[derive(Clone, Debug)]
46pub struct UsedVar<T, U>
47{
48    mod1: ModNodeRef<T, U>,
49    ident: String,
50}
51
52impl<T, U> UsedVar<T, U>
53{
54    /// Creates an object of used variable.
55    pub fn new(mod1: ModNodeRef<T, U>, ident: String) -> Self
56    { UsedVar { mod1, ident, } }
57
58    /// Returns the module.
59    pub fn mod1(&self) -> &ModNodeRef<T, U>
60    { &self.mod1 }
61
62    /// Returns the identifier.
63    pub fn ident(&self) -> &String
64    { &self.ident }
65}
66
67/// A structure of module node.
68///
69/// The module nodes creates a tree of modules that has modules and variables. The module node
70/// contains the modules which are the module nodes, the variables, and module value. Also, the
71/// module node has used modules and used variables. The used modules and the used variables are
72/// from other module, but also are available in the module node by identifiers.
73#[derive(Clone, Debug)]
74pub struct ModNode<T, U>
75{
76    used_mods: HashMap<String, ModNodeRef<T, U>>,
77    used_vars: HashMap<String, UsedVar<T, U>>,
78    mods: HashMap<String, Arc<RwLock<ModNode<T, U>>>>,
79    vars: HashMap<String, T>,
80    parent: Option<Weak<RwLock<ModNode<T, U>>>>,
81    value: U,
82}
83
84impl<T, U> ModNode<T, U>
85{
86    /// Creates a module node with the module value.
87    pub fn new(value: U) -> Self
88    {
89        ModNode {
90            used_mods: HashMap::new(),
91            used_vars: HashMap::new(),
92            mods: HashMap::new(),
93            vars: HashMap::new(),
94            parent: None,
95            value,
96        }
97    }
98    
99    /// Returns the used modules.
100    pub fn used_mods(&self) -> &HashMap<String, ModNodeRef<T, U>>
101    { &self.used_mods }
102
103    /// Returns `true` if the module node has the used module, otherwise `false`.
104    pub fn has_used_mod(&self, ident: &String) -> bool
105    { self.used_mods.contains_key(ident) }
106    
107    /// Returns the reference to the used module if the module node has the used module,
108    /// otherwise `None`.
109    pub fn used_mod(&self, ident: &String) -> Option<&ModNodeRef<T, U>>
110    { self.used_mods.get(ident) }
111
112    fn mod_to_mod_ref(mod1: &Arc<RwLock<ModNode<T, U>>>, mod2: Arc<RwLock<ModNode<T, U>>>) -> Result<ModNodeRef<T, U>>
113    {
114        let mut node = Some(mod1.clone());
115        loop {
116            match &node {
117                Some(tmp_node) => { 
118                    if Arc::ptr_eq(&tmp_node, &mod2) {
119                        return Ok(ModNodeRef::Weak(Arc::downgrade(&mod2)));
120                    }
121                    let parent = {
122                        let tmp_node_g = rw_lock_read(&**tmp_node)?;
123                        tmp_node_g.parent()
124                    };
125                    node = parent;
126                },
127                None => break,
128            }
129        }
130        Ok(ModNodeRef::Arc(mod2.clone()))
131    }
132    
133    /// Adds the used module to the module node.
134    pub fn add_used_mod(mod1: &Arc<RwLock<ModNode<T, U>>>, ident: String, used_mod: Arc<RwLock<ModNode<T, U>>>) -> Result<()>
135    {
136        let used_mod_ref = Self::mod_to_mod_ref(mod1, used_mod)?;
137        let mut mod_g = rw_lock_write(&**mod1)?;
138        mod_g.used_mods.insert(ident, used_mod_ref);
139        Ok(())
140    }
141
142    /// Removes the used module from the module node.
143    pub fn remove_used_mod(&mut self, ident: &String)
144    { self.used_mods.remove(ident); }
145
146    /// Returns the used variable from the module node.
147    pub fn used_vars(&self) -> &HashMap<String, UsedVar<T, U>>
148    { &self.used_vars }
149
150    /// Returns `true` if the module node has the used variable, otherwise `false`.
151    pub fn has_used_var(&self, ident: &String) -> bool
152    { self.used_vars.contains_key(ident) }
153    
154    /// Returns the object of used variable if the module node has the used variable, otherwise
155    /// `None`.
156    pub fn used_var(&self, ident: &String) -> Option<&UsedVar<T, U>>
157    { self.used_vars.get(ident) }
158
159    /// Adds the used variable to the module node.
160    pub fn add_used_var(mod1: &Arc<RwLock<ModNode<T, U>>>, ident: String, used_var_mod: Arc<RwLock<ModNode<T, U>>>, used_var_ident: String) -> Result<()>
161    {
162        let used_var_mod_ref = Self::mod_to_mod_ref(mod1, used_var_mod)?;
163        let mut mod_g = rw_lock_write(&**mod1)?;
164        mod_g.used_vars.insert(ident, UsedVar::new(used_var_mod_ref, used_var_ident));
165        Ok(())
166    }
167    
168    /// Removes the used variable from the module node.
169    pub fn remove_used_var(&mut self, ident: &String)
170    { self.used_vars.remove(ident); }
171
172    /// Returns the modules.
173    pub fn mods(&self) -> &HashMap<String, Arc<RwLock<ModNode<T, U>>>>
174    { &self.mods }
175
176    /// Returns `true` if the module node has the module, otherwise `false`.
177    pub fn has_mod(&self, ident: &String) -> bool
178    { self.mods.contains_key(ident) }
179    
180    /// Returns the module if the module node has the module, otherwise `None`.
181    pub fn mod1(&self, ident: &String) -> Option<&Arc<RwLock<ModNode<T, U>>>>
182    { self.mods.get(ident) }
183
184    /// Adds the module to the module node.
185    pub fn add_mod(parent: &Arc<RwLock<ModNode<T, U>>>, ident: String, child: Arc<RwLock<ModNode<T, U>>>) -> Result<()>
186    {
187        {
188            let mut child_g = rw_lock_write(&*child)?;
189            if child_g.parent.is_some() {
190                return Err(Error::AlreadyAddedModNode);
191            }
192            child_g.parent = Some(Arc::downgrade(&parent));
193        }
194        let mut parent_g = rw_lock_write(&**parent)?;
195        parent_g.remove_mod(&ident)?;
196        parent_g.mods.insert(ident, child);
197        Ok(())
198    }
199
200    /// Removes the module from the module node.
201    pub fn remove_mod(&mut self, ident: &String) -> Result<()>
202    {
203        match self.mods.get(ident) {
204            Some(child) => {
205                {
206                    let mut child_g = rw_lock_write(&*child)?;
207                    child_g.parent = None;
208                }
209                self.mods.remove(ident);
210                Ok(())
211            },
212            None => Ok(()),
213        }
214    }
215
216    /// Returns the variables.
217    pub fn vars(&self) -> &HashMap<String, T>
218    { &self.vars }
219
220    /// Returns `true` if the module node has the variable, otherwise `false`.
221    pub fn has_var(&self, ident: &String) -> bool
222    { self.vars.contains_key(ident) }
223
224    /// Returns the variable if the module node has the variable, otherwise `None`.
225    pub fn var(&self, ident: &String) -> Option<&T>
226    { self.vars.get(ident) }
227
228    /// Adds the variable to module node.
229    pub fn add_var(&mut self, ident: String, value: T)
230    { self.vars.insert(ident, value); }
231
232    /// Removes the variable from module node.
233    pub fn remove_var(&mut self, ident: &String)
234    { self.vars.remove(ident); }
235    
236    /// Returns the parent if the module node if the module node has the parent, otherwise `None`.
237    pub fn parent(&self) -> Option<Arc<RwLock<ModNode<T, U>>>>
238    {
239        match &self.parent{
240            Some(parent) => parent.upgrade(),
241            None => None,
242        }
243    }
244
245    /// Returns the module value.
246    pub fn value(&self) -> &U
247    { &self.value }
248    
249    /// Sets the module value.
250    pub fn set_value(&mut self, value: U)
251    { self.value = value; }
252    
253    /// Returns the module for the identifiers of modules if the module exists, otherwise `None`.
254    ///
255    /// If flag of used modules is set, the first identifier of module can refers to the used
256    /// module.
257    pub fn mod_from(root: &Arc<RwLock<ModNode<T, U>>>, idents: &[String], are_used_mods: bool) -> Result<Option<Arc<RwLock<ModNode<T, U>>>>>
258    {
259        let mut node = root.clone();
260        let mut is_first = true;
261        for ident in idents {
262            let child: Arc<RwLock<ModNode<T, U>>>;
263            {
264                let node_g = rw_lock_read(&*node)?;
265                child = match node_g.mods.get(ident) {
266                    Some(tmp_child) => tmp_child.clone(),
267                    None => {
268                        if is_first && are_used_mods {
269                            match node_g.used_mods.get(ident) {
270                                Some(tmp_child) => {
271                                    match tmp_child.to_arc() {
272                                        Some(child_arc) => child_arc,
273                                        None => return Ok(None),
274                                    }
275                                },
276                                None => return Ok(None),
277                            }
278                        } else {
279                            return Ok(None);
280                        }
281                    },
282                };
283            };
284            node = child;
285            is_first = false;
286        }
287        Ok(Some(node))
288    }
289}
290
291#[cfg(test)]
292mod tests;