1use std::path::{Path, PathBuf};
8
9use anyhow::Result;
10
11use crate::link::Link;
12use crate::link_storage::{ChangeObserver, LinkStorage};
13use crate::named_links::NamedLinks;
14use crate::pinned_types::{PinnedTypesAccess, PinnedTypesDecorator};
15
16pub trait NamedTypes {
17 fn get_name(&mut self, link: u32) -> Result<Option<String>>;
18 fn set_name(&mut self, link: u32, name: &str) -> Result<u32>;
19 fn get_by_name(&mut self, name: &str) -> Result<Option<u32>>;
20 fn remove_name(&mut self, link: u32) -> Result<()>;
21}
22
23pub struct NamedTypesDecorator {
24 pinned_types_decorator: PinnedTypesDecorator,
25 names_links: LinkStorage,
26 trace: bool,
27}
28
29impl NamedTypesDecorator {
30 pub fn new<P>(database_filename: P, trace: bool) -> Result<Self>
31 where
32 P: AsRef<Path>,
33 {
34 let names_database_filename =
35 Self::make_names_database_filename(database_filename.as_ref());
36 Self::with_names_database_path(database_filename, names_database_filename, trace)
37 }
38
39 pub fn with_names_database_path<P, N>(
40 database_filename: P,
41 names_database_filename: N,
42 trace: bool,
43 ) -> Result<Self>
44 where
45 P: AsRef<Path>,
46 N: AsRef<Path>,
47 {
48 let database_path = path_to_string(database_filename.as_ref());
49 let names_database_path = path_to_string(names_database_filename.as_ref());
50 let links = LinkStorage::new(&database_path, trace)?;
51 let names_links = LinkStorage::new(&names_database_path, trace)?;
52 Ok(Self::from_link_storages_with_trace(
53 links,
54 names_links,
55 trace,
56 ))
57 }
58
59 pub fn from_link_storages(links: LinkStorage, names_links: LinkStorage) -> Self {
60 Self::from_link_storages_with_trace(links, names_links, false)
61 }
62
63 pub fn from_pinned_types_decorator(
64 pinned_types_decorator: PinnedTypesDecorator,
65 names_links: LinkStorage,
66 ) -> Self {
67 Self::from_decorators_with_trace(pinned_types_decorator, names_links, false)
68 }
69
70 pub fn make_names_database_filename<P>(database_filename: P) -> PathBuf
71 where
72 P: AsRef<Path>,
73 {
74 let path = database_filename.as_ref();
75 let filename_without_extension = path
76 .file_stem()
77 .and_then(|value| value.to_str())
78 .unwrap_or_default();
79 let names_filename = format!("{filename_without_extension}.names.links");
80
81 path.parent()
82 .filter(|parent| !parent.as_os_str().is_empty())
83 .map(|parent| parent.join(&names_filename))
84 .unwrap_or_else(|| PathBuf::from(names_filename))
85 }
86
87 pub fn links(&self) -> &LinkStorage {
88 self.pinned_types_decorator.links()
89 }
90
91 pub fn links_mut(&mut self) -> &mut LinkStorage {
92 self.pinned_types_decorator.links_mut()
93 }
94
95 pub fn pinned_types_decorator(&self) -> &PinnedTypesDecorator {
96 &self.pinned_types_decorator
97 }
98
99 pub fn pinned_types_decorator_mut(&mut self) -> &mut PinnedTypesDecorator {
100 &mut self.pinned_types_decorator
101 }
102
103 pub fn names_links(&self) -> &LinkStorage {
104 &self.names_links
105 }
106
107 pub fn names_links_mut(&mut self) -> &mut LinkStorage {
108 &mut self.names_links
109 }
110
111 pub fn into_link_storages(self) -> (LinkStorage, LinkStorage) {
112 (
113 self.pinned_types_decorator.into_link_storage(),
114 self.names_links,
115 )
116 }
117
118 pub fn save(&self) -> Result<()> {
119 self.pinned_types_decorator.save()?;
120 self.names_links.save()?;
121 Ok(())
122 }
123
124 pub fn create(&mut self, source: u32, target: u32) -> u32 {
125 self.pinned_types_decorator.create(source, target)
126 }
127
128 pub fn ensure_created(&mut self, id: u32) -> u32 {
129 self.pinned_types_decorator.ensure_created(id)
130 }
131
132 pub fn get(&self, id: u32) -> Option<&Link> {
133 self.pinned_types_decorator.get(id)
134 }
135
136 pub fn exists(&self, id: u32) -> bool {
137 self.pinned_types_decorator.exists(id)
138 }
139
140 pub fn update(&mut self, id: u32, source: u32, target: u32) -> Result<Link> {
141 self.update_observed(id, source, target, &mut |_, _| {})
142 }
143
144 pub fn update_observed(
158 &mut self,
159 id: u32,
160 source: u32,
161 target: u32,
162 observer: ChangeObserver<'_>,
163 ) -> Result<Link> {
164 let mut deleted = Vec::new();
165 let updated = self.pinned_types_decorator.update_observed(
166 id,
167 source,
168 target,
169 &mut |before, after| {
170 if after.is_null() && !before.is_null() {
171 deleted.push(before.index);
172 }
173 observer(before, after);
174 },
175 )?;
176 self.remove_names(&deleted)?;
177 Ok(updated)
178 }
179
180 pub fn delete(&mut self, id: u32) -> Result<Link> {
181 self.delete_observed(id, &mut |_, _| {})
182 }
183
184 pub fn delete_observed(&mut self, id: u32, observer: ChangeObserver<'_>) -> Result<Link> {
189 let mut deleted = Vec::new();
190 let removed = self
191 .pinned_types_decorator
192 .delete_observed(id, &mut |before, after| {
193 if after.is_null() && !before.is_null() {
194 deleted.push(before.index);
195 }
196 observer(before, after);
197 })?;
198 if !deleted.contains(&id) {
199 deleted.push(id);
200 }
201 self.remove_names(&deleted)?;
202 Ok(removed)
203 }
204
205 fn remove_names(&mut self, indexes: &[u32]) -> Result<()> {
206 for index in indexes {
207 self.remove_name(*index)?;
208 }
209 Ok(())
210 }
211
212 pub fn all(&self) -> Vec<&Link> {
213 self.pinned_types_decorator.all()
214 }
215
216 pub fn query(
217 &self,
218 index: Option<u32>,
219 source: Option<u32>,
220 target: Option<u32>,
221 ) -> Vec<&Link> {
222 self.pinned_types_decorator.query(index, source, target)
223 }
224
225 pub fn search(&self, source: u32, target: u32) -> Option<u32> {
226 self.pinned_types_decorator.search(source, target)
227 }
228
229 pub fn get_or_create(&mut self, source: u32, target: u32) -> u32 {
230 self.pinned_types_decorator.get_or_create(source, target)
231 }
232
233 fn from_link_storages_with_trace(
234 links: LinkStorage,
235 names_links: LinkStorage,
236 trace: bool,
237 ) -> Self {
238 Self::from_decorators_with_trace(
239 PinnedTypesDecorator::from_link_storage(links),
240 names_links,
241 trace,
242 )
243 }
244
245 fn from_decorators_with_trace(
246 pinned_types_decorator: PinnedTypesDecorator,
247 names_links: LinkStorage,
248 trace: bool,
249 ) -> Self {
250 Self {
251 pinned_types_decorator,
252 names_links,
253 trace,
254 }
255 }
256
257 fn with_named_links<T>(
258 &mut self,
259 action: impl FnOnce(&mut NamedLinks<'_>) -> Result<T>,
260 ) -> Result<T> {
261 let mut named_links = NamedLinks::new(&mut self.names_links)?;
262 action(&mut named_links)
263 }
264}
265
266impl NamedTypes for NamedTypesDecorator {
267 fn get_name(&mut self, link: u32) -> Result<Option<String>> {
268 if self.trace {
269 eprintln!("[TRACE] NamedTypesDecorator get_name for link {link}");
270 }
271 self.with_named_links(|named_links| named_links.get_name_by_external_reference(link))
272 }
273
274 fn set_name(&mut self, link: u32, name: &str) -> Result<u32> {
275 if self.trace {
276 eprintln!("[TRACE] NamedTypesDecorator set_name for link {link}: {name}");
277 }
278 if let Some(existing_link_with_name) = self.get_by_name(name)? {
279 if existing_link_with_name != link {
280 self.remove_name(existing_link_with_name)?;
281 }
282 }
283 self.remove_name(link)?;
284 self.with_named_links(|named_links| named_links.set_name_for_external_reference(link, name))
285 }
286
287 fn get_by_name(&mut self, name: &str) -> Result<Option<u32>> {
288 if self.trace {
289 eprintln!("[TRACE] NamedTypesDecorator get_by_name for name {name}");
290 }
291 self.with_named_links(|named_links| named_links.get_external_reference_by_name(name))
292 }
293
294 fn remove_name(&mut self, link: u32) -> Result<()> {
295 if self.trace {
296 eprintln!("[TRACE] NamedTypesDecorator remove_name for link {link}");
297 }
298 self.with_named_links(|named_links| named_links.remove_name_by_external_reference(link))
299 }
300}
301
302impl PinnedTypesAccess for NamedTypesDecorator {
303 fn pinned_types(&mut self, count: usize) -> Result<Vec<u32>> {
304 self.pinned_types_decorator.pinned_types(count)
305 }
306}
307
308fn path_to_string(path: &Path) -> String {
309 path.to_string_lossy().into_owned()
310}