1use std::path::{Path, PathBuf};
8
9use anyhow::Result;
10
11use crate::link::Link;
12use crate::link_storage::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.pinned_types_decorator.update(id, source, target)
142 }
143
144 pub fn delete(&mut self, id: u32) -> Result<Link> {
145 let deleted = self.pinned_types_decorator.delete(id)?;
146 self.remove_name(id)?;
147 Ok(deleted)
148 }
149
150 pub fn all(&self) -> Vec<&Link> {
151 self.pinned_types_decorator.all()
152 }
153
154 pub fn query(
155 &self,
156 index: Option<u32>,
157 source: Option<u32>,
158 target: Option<u32>,
159 ) -> Vec<&Link> {
160 self.pinned_types_decorator.query(index, source, target)
161 }
162
163 pub fn search(&self, source: u32, target: u32) -> Option<u32> {
164 self.pinned_types_decorator.search(source, target)
165 }
166
167 pub fn get_or_create(&mut self, source: u32, target: u32) -> u32 {
168 self.pinned_types_decorator.get_or_create(source, target)
169 }
170
171 fn from_link_storages_with_trace(
172 links: LinkStorage,
173 names_links: LinkStorage,
174 trace: bool,
175 ) -> Self {
176 Self::from_decorators_with_trace(
177 PinnedTypesDecorator::from_link_storage(links),
178 names_links,
179 trace,
180 )
181 }
182
183 fn from_decorators_with_trace(
184 pinned_types_decorator: PinnedTypesDecorator,
185 names_links: LinkStorage,
186 trace: bool,
187 ) -> Self {
188 Self {
189 pinned_types_decorator,
190 names_links,
191 trace,
192 }
193 }
194
195 fn with_named_links<T>(
196 &mut self,
197 action: impl FnOnce(&mut NamedLinks<'_>) -> Result<T>,
198 ) -> Result<T> {
199 let mut named_links = NamedLinks::new(&mut self.names_links)?;
200 action(&mut named_links)
201 }
202}
203
204impl NamedTypes for NamedTypesDecorator {
205 fn get_name(&mut self, link: u32) -> Result<Option<String>> {
206 if self.trace {
207 eprintln!("[TRACE] NamedTypesDecorator get_name for link {link}");
208 }
209 self.with_named_links(|named_links| named_links.get_name_by_external_reference(link))
210 }
211
212 fn set_name(&mut self, link: u32, name: &str) -> Result<u32> {
213 if self.trace {
214 eprintln!("[TRACE] NamedTypesDecorator set_name for link {link}: {name}");
215 }
216 if let Some(existing_link_with_name) = self.get_by_name(name)? {
217 if existing_link_with_name != link {
218 self.remove_name(existing_link_with_name)?;
219 }
220 }
221 self.remove_name(link)?;
222 self.with_named_links(|named_links| named_links.set_name_for_external_reference(link, name))
223 }
224
225 fn get_by_name(&mut self, name: &str) -> Result<Option<u32>> {
226 if self.trace {
227 eprintln!("[TRACE] NamedTypesDecorator get_by_name for name {name}");
228 }
229 self.with_named_links(|named_links| named_links.get_external_reference_by_name(name))
230 }
231
232 fn remove_name(&mut self, link: u32) -> Result<()> {
233 if self.trace {
234 eprintln!("[TRACE] NamedTypesDecorator remove_name for link {link}");
235 }
236 self.with_named_links(|named_links| named_links.remove_name_by_external_reference(link))
237 }
238}
239
240impl PinnedTypesAccess for NamedTypesDecorator {
241 fn pinned_types(&mut self, count: usize) -> Result<Vec<u32>> {
242 self.pinned_types_decorator.pinned_types(count)
243 }
244}
245
246fn path_to_string(path: &Path) -> String {
247 path.to_string_lossy().into_owned()
248}