1use crate::types::Handle;
18use indexmap::IndexMap;
19
20pub mod layer;
21pub mod linetype;
22pub mod textstyle;
23pub mod block_record;
24pub mod dimstyle;
25pub mod appid;
26pub mod view;
27pub mod vport;
28pub mod ucs;
29
30pub use layer::{Layer, LayerFlags};
31pub use linetype::{LineType, LineTypeElement};
32pub use textstyle::{TextStyle, TextGenerationFlags};
33pub use block_record::BlockRecord;
34pub use dimstyle::DimStyle;
35pub use appid::AppId;
36pub use view::View;
37pub use vport::VPort;
38pub use ucs::Ucs;
39
40pub trait TableEntry {
42 fn handle(&self) -> Handle;
44
45 fn set_handle(&mut self, handle: Handle);
47
48 fn name(&self) -> &str;
50
51 fn set_name(&mut self, name: String);
53
54 fn is_standard(&self) -> bool {
56 false
57 }
58}
59
60#[derive(Debug, Clone, PartialEq)]
62#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
63pub struct Table<T: TableEntry> {
64 entries: IndexMap<String, T>,
66 handle: Handle,
68}
69
70impl<T: TableEntry> Table<T> {
71 pub fn new() -> Self {
73 Table {
74 entries: IndexMap::new(),
75 handle: Handle::NULL,
76 }
77 }
78
79 pub fn with_handle(handle: Handle) -> Self {
81 Table {
82 entries: IndexMap::new(),
83 handle,
84 }
85 }
86
87 pub fn handle(&self) -> Handle {
89 self.handle
90 }
91
92 pub fn set_handle(&mut self, handle: Handle) {
94 self.handle = handle;
95 }
96
97 pub fn add(&mut self, entry: T) -> Result<(), String> {
99 let name = entry.name().to_uppercase();
100 if self.entries.contains_key(&name) {
101 return Err(format!("Entry '{}' already exists in table", entry.name()));
102 }
103 self.entries.insert(name, entry);
104 Ok(())
105 }
106
107 pub fn add_or_replace(&mut self, entry: T) {
109 let name = entry.name().to_uppercase();
110 self.entries.insert(name, entry);
111 }
112
113 pub fn get(&self, name: &str) -> Option<&T> {
115 self.entries.get(&name.to_uppercase())
116 }
117
118 pub fn get_mut(&mut self, name: &str) -> Option<&mut T> {
120 self.entries.get_mut(&name.to_uppercase())
121 }
122
123 pub fn remove(&mut self, name: &str) -> Option<T> {
125 self.entries.shift_remove(&name.to_uppercase())
126 }
127
128 pub fn contains(&self, name: &str) -> bool {
130 self.entries.contains_key(&name.to_uppercase())
131 }
132
133 pub fn len(&self) -> usize {
135 self.entries.len()
136 }
137
138 pub fn is_empty(&self) -> bool {
140 self.entries.is_empty()
141 }
142
143 pub fn iter(&self) -> impl Iterator<Item = &T> {
145 self.entries.values()
146 }
147
148 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
150 self.entries.values_mut()
151 }
152
153 pub fn names(&self) -> impl Iterator<Item = &str> {
155 self.entries.values().map(|e| e.name())
156 }
157
158 pub fn clear(&mut self) {
160 self.entries.clear();
161 }
162}
163
164impl<T: TableEntry> Default for Table<T> {
165 fn default() -> Self {
166 Self::new()
167 }
168}
169
170#[cfg(test)]
171mod tests {
172 use super::*;
173
174 #[derive(Debug, Clone)]
176 struct MockEntry {
177 handle: Handle,
178 name: String,
179 }
180
181 impl TableEntry for MockEntry {
182 fn handle(&self) -> Handle {
183 self.handle
184 }
185
186 fn set_handle(&mut self, handle: Handle) {
187 self.handle = handle;
188 }
189
190 fn name(&self) -> &str {
191 &self.name
192 }
193
194 fn set_name(&mut self, name: String) {
195 self.name = name;
196 }
197 }
198
199 #[test]
200 fn test_table_add_and_get() {
201 let mut table = Table::new();
202 let entry = MockEntry {
203 handle: Handle::new(1),
204 name: "Test".to_string(),
205 };
206
207 assert!(table.add(entry).is_ok());
208 assert!(table.contains("Test"));
209 assert!(table.contains("test")); assert_eq!(table.len(), 1);
211 }
212
213 #[test]
214 fn test_table_duplicate_entry() {
215 let mut table = Table::new();
216 let entry1 = MockEntry {
217 handle: Handle::new(1),
218 name: "Test".to_string(),
219 };
220 let entry2 = MockEntry {
221 handle: Handle::new(2),
222 name: "test".to_string(), };
224
225 assert!(table.add(entry1).is_ok());
226 assert!(table.add(entry2).is_err()); }
228
229 #[test]
230 fn test_table_remove() {
231 let mut table = Table::new();
232 let entry = MockEntry {
233 handle: Handle::new(1),
234 name: "Test".to_string(),
235 };
236
237 table.add(entry).unwrap();
238 assert_eq!(table.len(), 1);
239
240 let removed = table.remove("test");
241 assert!(removed.is_some());
242 assert_eq!(table.len(), 0);
243 }
244}
245
246