donet_core/dckeyword.rs
1/*
2 This file is part of Donet.
3
4 Copyright © 2024-2025 Max Rodriguez <[email protected]>
5
6 Donet is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Affero General Public License,
8 as published by the Free Software Foundation, either version 3
9 of the License, or (at your option) any later version.
10
11 Donet is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Affero General Public License for more details.
15
16 You should have received a copy of the GNU Affero General Public
17 License along with Donet. If not, see <https://www.gnu.org/licenses/>.
18*/
19
20//! Representation of arbitrary and historical
21//! keywords as defined in the DC file.
22
23use crate::hashgen::*;
24
25#[derive(Debug, PartialEq, Eq)]
26pub struct DCKeyword(String);
27
28impl std::fmt::Display for DCKeyword {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 write!(f, "keyword ")?;
31 f.write_str(&self.0)?;
32 write!(f, ";")
33 }
34}
35
36impl LegacyDCHash for DCKeyword {
37 fn generate_hash(&self, hashgen: &mut DCHashGenerator) {
38 hashgen.add_string(self.0.clone());
39 }
40}
41
42impl DCKeyword {
43 #[inline]
44 pub fn get_name(&self) -> String {
45 self.0.clone()
46 }
47}
48
49/// Represents the two types of inputs that `DCKeywordList.has_keyword`
50/// accepts for looking up a Keyword. In Panda and Astron, the
51/// `has_keyword` method is overloaded instead.
52pub enum IdentifyKeyword {
53 ByStruct(DCKeyword),
54 ByName(String),
55}
56
57/// This is a list of [`DCKeyword`] structures, which represent
58/// communication keywords that may be set on a particular field.
59#[derive(Debug)]
60pub struct DCKeywordList {
61 keywords: Vec<DCKeyword>,
62}
63/* TODO!
64impl std::cmp::PartialEq for DCKeywordList {
65 fn eq(&self, other: &Self) -> bool {
66 let target_kw_map: KeywordName2Keyword = other._get_keywords_by_name_map();
67
68 // If our maps are different sizes, they are already not the same.
69 if self.kw_name_2_keyword.len() != target_kw_map.len() {
70 return false;
71 }
72
73 // Since MultiMap does not implement the Eq trait,
74 // we have to iterate through both maps and compare.
75 for key in self.kw_name_2_keyword.keys() {
76 if !target_kw_map.contains_key(key) {
77 return false;
78 }
79 }
80 true // no differences found
81 }
82}*/
83
84impl std::fmt::Display for DCKeywordList {
85 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86 for (i, kw) in self.keywords.iter().enumerate() {
87 // We do not call the fmt::Display impl of [`DCKeyword`] here,
88 // as that formats it as a declaration, not use in a field's
89 // keyword list. So, we just need to format the kw identifier.
90 f.write_str(&kw.0)?;
91
92 if i != self.keywords.len() - 1 {
93 write!(f, " ")?;
94 }
95 }
96 writeln!(f, ";")
97 }
98}
99
100impl LegacyDCHash for DCKeywordList {
101 fn generate_hash(&self, hashgen: &mut DCHashGenerator) {
102 hashgen.add_int(self.keywords.len().try_into().unwrap());
103
104 for keyword in &self.keywords {
105 keyword.generate_hash(hashgen);
106 }
107 }
108}
109
110impl DCKeywordList {
111 /// Returns the number of keywords in this keyword list.
112 pub fn get_num_keywords(&self) -> usize {
113 self.keywords.len()
114 }
115
116 /// Returns `true` if given keyword identifier or struct
117 /// is present in this keyword list.
118 pub fn has_keyword(&self, kw: IdentifyKeyword) -> bool {
119 match kw {
120 IdentifyKeyword::ByName(_kw_id) => todo!("TODO!"),
121 IdentifyKeyword::ByStruct(kw_obj) => {
122 for keyword in &self.keywords {
123 if *keyword == kw_obj {
124 return true;
125 }
126 }
127 false // no match found
128 }
129 }
130 }
131
132 /// Returns [`DCKeyword`] reference by index, wrapped in an Option.
133 pub fn get_keyword(&self, index: usize) -> Option<&DCKeyword> {
134 self.keywords.get(index)
135 }
136}
137
138pub(crate) mod semantics {
139 /* TODO!
140 pub fn add_keyword(element: &mut DCKeywordList, keyword: DCKeyword) -> Result<(), ()> {
141 let kw_name: String = keyword.name.clone(); // avoid moving 'name'
142
143 if self.kw_name_2_keyword.get(&kw_name).is_some() {
144 return Err(()); // keyword is already in our list!
145 }
146
147 self.keywords.push(Rc::new(keyword));
148 self.kw_name_2_keyword
149 .insert(kw_name, self.keywords.last().unwrap().clone());
150 Ok(())
151 }
152
153 /// Overwrites the DCKeywords of this list with the target's DCKeywords.
154 pub fn copy_keywords(element: &mut DCKeywordList, target: &DCKeywordList) {
155 let target_kw_array: Vec<Rc<DCKeyword>> = target._get_keyword_list();
156 let target_kw_map: MultiMap<String, Rc<DCKeyword>> = target._get_keywords_by_name_map();
157
158 self.keywords = target_kw_array; // old vec will be dropped from memory
159 self.kw_name_2_keyword = target_kw_map;
160 }*/
161}