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}