Skip to main content

link_cli/
named_types.rs

1//! Named type decorator for Rust link storage.
2//!
3//! This mirrors the C# `NamedTypesDecorator<uint>` role: link operations and
4//! pinned type access are delegated through `PinnedTypesDecorator`, while names
5//! are stored as external references in a separate links database.
6
7use 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}