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