Skip to main content

zerodds_corba_dnc/
repository.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 ZeroDDS Contributors
3
4//! RepositoryManager — D&C §8.
5//!
6//! Spec §8.1.1: `RepositoryManager` haelt die `PackageConfiguration`-
7//! Bindings im System. Deployers laden Packages hinein, Executors
8//! konsumieren sie.
9
10use alloc::collections::BTreeMap;
11use alloc::string::String;
12use alloc::vec::Vec;
13
14use crate::plan::PackageConfiguration;
15
16/// In-Memory-RepositoryManager — D&C §8.
17#[derive(Debug, Default, Clone, PartialEq, Eq)]
18pub struct RepositoryManager {
19    packages: BTreeMap<String, PackageConfiguration>,
20}
21
22impl RepositoryManager {
23    /// Konstruktor.
24    #[must_use]
25    pub fn new() -> Self {
26        Self::default()
27    }
28
29    /// Spec §8.1.2 `installPackage` — registriert ein Package unter
30    /// seinem `package.label`. Ueberschreibt bei Duplikat.
31    pub fn install_package(&mut self, pkg: PackageConfiguration) {
32        let key = pkg.label.clone();
33        self.packages.insert(key, pkg);
34    }
35
36    /// Spec §8.1.3 `findPackageByName` — sucht ein Package per Label.
37    #[must_use]
38    pub fn find_package(&self, label: &str) -> Option<&PackageConfiguration> {
39        self.packages.get(label)
40    }
41
42    /// Spec §8.1.4 `deletePackage` — entfernt ein Package; gibt
43    /// `false` wenn nicht gefunden.
44    pub fn delete_package(&mut self, label: &str) -> bool {
45        self.packages.remove(label).is_some()
46    }
47
48    /// Spec §8.1.5 `getAllPackageNames` — Liste aller Package-Labels.
49    #[must_use]
50    pub fn list_packages(&self) -> Vec<String> {
51        self.packages.keys().cloned().collect()
52    }
53}
54
55#[cfg(test)]
56#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
57mod tests {
58    use super::*;
59    use crate::plan::ComponentPackageDescription;
60    use alloc::string::ToString;
61
62    fn make_pkg(label: &str) -> PackageConfiguration {
63        PackageConfiguration {
64            label: label.into(),
65            uuid: alloc::format!("uuid-{label}"),
66            package: ComponentPackageDescription {
67                label: label.into(),
68                ..ComponentPackageDescription::default()
69            },
70            selected_implementation: 0,
71        }
72    }
73
74    #[test]
75    fn install_and_find_round_trip() {
76        let mut r = RepositoryManager::new();
77        r.install_package(make_pkg("Echo"));
78        assert!(r.find_package("Echo").is_some());
79        assert_eq!(r.find_package("NoSuch"), None);
80    }
81
82    #[test]
83    fn list_packages_returns_all_labels() {
84        let mut r = RepositoryManager::new();
85        r.install_package(make_pkg("A"));
86        r.install_package(make_pkg("B"));
87        let mut names = r.list_packages();
88        names.sort();
89        assert_eq!(names, alloc::vec!["A".to_string(), "B".to_string()]);
90    }
91
92    #[test]
93    fn delete_existing_returns_true() {
94        let mut r = RepositoryManager::new();
95        r.install_package(make_pkg("X"));
96        assert!(r.delete_package("X"));
97        assert!(r.find_package("X").is_none());
98    }
99
100    #[test]
101    fn delete_unknown_returns_false() {
102        let mut r = RepositoryManager::new();
103        assert!(!r.delete_package("X"));
104    }
105
106    #[test]
107    fn install_overwrites_duplicate() {
108        let mut r = RepositoryManager::new();
109        let mut pkg = make_pkg("Echo");
110        pkg.uuid = "first".into();
111        r.install_package(pkg);
112        let mut pkg2 = make_pkg("Echo");
113        pkg2.uuid = "second".into();
114        r.install_package(pkg2);
115        assert_eq!(r.find_package("Echo").unwrap().uuid, "second");
116    }
117}