plux_rs/info.rs
1use std::{fmt::Display, path::PathBuf};
2
3use semver::{Version, VersionReq};
4use serde::{Deserialize, Serialize};
5
6use crate::{Bundle, Plugin};
7
8/// Complete information about a plugin.
9///
10/// PluginInfo combines the plugin's filesystem location, bundle metadata, and
11/// dependency information into a single structure used throughout the Plux system.
12///
13/// # Type Parameters
14///
15/// * `I` - The type implementing the Info trait (contains dependency information)
16///
17/// # Fields
18///
19/// * `path` - Filesystem path to the plugin file or directory
20/// * `bundle` - Bundle metadata (id, version, format)
21/// * `info` - Dependency and configuration information
22pub struct PluginInfo<I: Info> {
23 /// Filesystem path to the plugin
24 pub path: PathBuf,
25 /// Bundle metadata for the plugin
26 pub bundle: Bundle,
27 /// Dependency and configuration information
28 pub info: I,
29}
30
31/// Trait for plugin information and dependencies.
32///
33/// The Info trait defines the interface for accessing a plugin's dependency information.
34/// Implementations of this trait provide details about what other plugins this plugin
35/// depends on for its operation.
36///
37/// # Required Methods
38///
39/// * `depends` - Returns the list of required dependencies
40/// * `optional_depends` - Returns the list of optional dependencies
41///
42/// # Example
43///
44/// ```rust
45/// use plux_rs::{Info, Depend};
46///
47/// struct MyInfo {
48/// required: Vec<Depend>,
49/// optional: Vec<Depend>,
50/// }
51///
52/// impl Info for MyInfo {
53/// fn depends(&self) -> &Vec<Depend> {
54/// &self.required
55/// }
56///
57/// fn optional_depends(&self) -> &Vec<Depend> {
58/// &self.optional
59/// }
60/// }
61/// ```
62pub trait Info: Send + Sync {
63 /// Returns the list of required dependencies for this plugin.
64 ///
65 /// Required dependencies must be available and loaded for the plugin to function.
66 ///
67 /// # Returns
68 ///
69 /// Returns a reference to a vector of required dependencies.
70 fn depends(&self) -> &Vec<Depend>;
71
72 /// Returns the list of optional dependencies for this plugin.
73 ///
74 /// Optional dependencies enhance functionality but are not required for basic operation.
75 ///
76 /// # Returns
77 ///
78 /// Returns a reference to a vector of optional dependencies.
79 fn optional_depends(&self) -> &Vec<Depend>;
80}
81
82/// Represents a dependency on another plugin.
83///
84/// A Depend specifies a plugin that must be available, including both the plugin's
85/// identifier and the acceptable version range.
86///
87/// # Fields
88///
89/// * `id` - The identifier of the required plugin
90/// * `version` - Version requirement specifying acceptable versions
91///
92/// # Examples
93///
94/// ```rust
95/// use plux_rs::Depend;
96/// use semver::VersionReq;
97///
98/// // Require any version 1.x of the "logger" plugin
99/// let dep1 = Depend::new("logger".to_string(), VersionReq::parse("1.*").unwrap());
100///
101/// // Require exactly version 2.0.0 of the "database" plugin
102/// let dep2 = Depend::new("database".to_string(), VersionReq::parse("=2.0.0").unwrap());
103/// ```
104#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
105pub struct Depend {
106 /// The identifier of the required plugin
107 pub id: String,
108 /// Version requirement for the dependency
109 pub version: VersionReq,
110}
111
112/// Standard implementation of the Info trait.
113///
114/// StdInfo provides a basic implementation of plugin information with lists of
115/// required and optional dependencies. This is the default implementation used
116/// by most plugin managers.
117///
118/// # Fields
119///
120/// * `depends` - List of plugins required for this plugin to function
121/// * `optional_depends` - List of plugins that enhance functionality but are not required
122///
123/// # Examples
124///
125/// ```rust
126/// use plux_rs::{StdInfo, Depend};
127/// use semver::VersionReq;
128///
129/// let mut info = StdInfo::new();
130/// info.depends.push(Depend::new("core".to_string(), VersionReq::parse("1.0").unwrap()));
131/// info.optional_depends.push(Depend::new("ui".to_string(), VersionReq::parse("2.*").unwrap()));
132/// ```
133#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
134pub struct StdInfo {
135 /// Required dependencies for this plugin
136 pub depends: Vec<Depend>,
137 /// Optional dependencies that enhance functionality
138 pub optional_depends: Vec<Depend>,
139}
140
141impl Depend {
142 /// Creates a new dependency specification.
143 ///
144 /// # Parameters
145 ///
146 /// * `name` - The identifier of the required plugin
147 /// * `version` - Version requirement for the dependency
148 ///
149 /// # Returns
150 ///
151 /// Returns a new Depend instance.
152 ///
153 /// # Example
154 ///
155 /// ```rust
156 /// use plux_rs::Depend;
157 /// use semver::VersionReq;
158 ///
159 /// let dependency = Depend::new("logger".to_string(), VersionReq::parse("1.0").unwrap());
160 /// ```
161 pub const fn new(name: String, version: VersionReq) -> Self {
162 Self { id: name, version }
163 }
164}
165
166impl Display for Depend {
167 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
168 write!(f, "{}[{}]", self.id, self.version)
169 }
170}
171
172impl<ID: AsRef<str>> PartialEq<(ID, &Version)> for Depend {
173 fn eq(&self, (id, version): &(ID, &Version)) -> bool {
174 self.id == id.as_ref() && self.version.matches(*version)
175 }
176}
177
178impl PartialEq<Bundle> for Depend {
179 fn eq(&self, Bundle { id, version, .. }: &Bundle) -> bool {
180 self.id == *id && self.version.matches(version)
181 }
182}
183
184impl<O: Send + Sync, I: Info> PartialEq<Plugin<'_, O, I>> for Depend {
185 fn eq(&self, other: &Plugin<'_, O, I>) -> bool {
186 self.id == other.info.bundle.id && self.version.matches(&other.info.bundle.version)
187 }
188}
189
190impl StdInfo {
191 /// Creates a new StdInfo instance with no dependencies.
192 ///
193 /// # Returns
194 ///
195 /// Returns a new StdInfo with empty dependency lists.
196 ///
197 /// # Example
198 ///
199 /// ```rust
200 /// use plux_rs::StdInfo;
201 ///
202 /// let info = StdInfo::new();
203 /// assert!(info.depends.is_empty());
204 /// assert!(info.optional_depends.is_empty());
205 /// ```
206 pub const fn new() -> Self {
207 Self {
208 depends: vec![],
209 optional_depends: vec![],
210 }
211 }
212}
213
214impl Info for StdInfo {
215 fn depends(&self) -> &Vec<Depend> {
216 &self.depends
217 }
218
219 fn optional_depends(&self) -> &Vec<Depend> {
220 &self.optional_depends
221 }
222}
223
224impl Display for StdInfo {
225 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
226 write!(
227 f,
228 "Dependencies: {};{}Optional dependencies: {}",
229 self.depends
230 .iter()
231 .map(|d| d.to_string())
232 .collect::<Vec<_>>()
233 .join(", "),
234 f.alternate().then_some('\n').unwrap_or(' '),
235 self.optional_depends
236 .iter()
237 .map(|d| d.to_string())
238 .collect::<Vec<_>>()
239 .join(", ")
240 )
241 }
242}