plux_rs/
plugin.rs

1use std::{cmp::Ordering, fmt::Debug, sync::Arc};
2
3use semver::Version;
4
5use crate::{
6    function::Function,
7    utils::{PluginCallFunctionError, PluginCallRequestError, PluginRegisterFunctionError, Ptr},
8    variable::Variable,
9    Bundle, Depend, Info, Manager, PluginInfo, Registry,
10};
11
12pub struct Plugin<'a, O: Send + Sync, I: Info> {
13    pub(crate) manager: Ptr<'a, Box<dyn Manager<'a, O, I>>>,
14    pub(crate) info: PluginInfo<I>,
15    pub(crate) is_load: bool,
16    pub(crate) requests: Vec<Box<dyn Function<Output = O>>>,
17    pub(crate) registry: Registry<O>,
18}
19
20impl<'a, O: Send + Sync, I: Info> Plugin<'a, O, I> {
21    pub(crate) const fn new(
22        manager: Ptr<'a, Box<dyn Manager<'a, O, I>>>,
23        info: PluginInfo<I>,
24    ) -> Self {
25        Self {
26            manager,
27            info,
28            is_load: false,
29            requests: vec![],
30            registry: vec![],
31        }
32    }
33
34    pub const fn info(&self) -> &PluginInfo<I> {
35        &self.info
36    }
37
38    pub const fn is_load(&self) -> bool {
39        self.is_load
40    }
41
42    pub const fn get_requests(&self) -> &Vec<Box<dyn Function<Output = O>>> {
43        &self.requests
44    }
45
46    pub fn call_request(&self, name: &str, args: &[Variable]) -> Result<O, PluginCallRequestError> {
47        self.requests
48            .iter()
49            .find_map(|request| match request.name() == name {
50                true => Some(request.call(args)),
51                false => None,
52            })
53            .ok_or(PluginCallRequestError::NotFound)
54    }
55
56    pub const fn get_registry(&self) -> &Registry<O> {
57        &self.registry
58    }
59
60    pub fn register_function<F>(&mut self, function: F) -> Result<(), PluginRegisterFunctionError>
61    where
62        F: Function<Output = O> + 'static,
63    {
64        let find_function = self
65            .registry
66            .iter()
67            .find(|&f| f.as_ref() == &function as &dyn Function<Output = O>);
68
69        match find_function {
70            Some(_) => Err(PluginRegisterFunctionError::AlreadyExists(function.name())),
71            None => Ok(self.registry.push(Arc::new(function))),
72        }
73    }
74
75    pub fn call_function(
76        &self,
77        name: &str,
78        args: &[Variable],
79    ) -> Result<O, PluginCallFunctionError> {
80        self.registry
81            .iter()
82            .find_map(|function| match function.name() == name {
83                true => Some(function.call(args)),
84                false => None,
85            })
86            .ok_or(PluginCallFunctionError::NotFound)
87    }
88}
89
90impl<O: Send + Sync, I: Info> PartialEq for Plugin<'_, O, I> {
91    fn eq(&self, other: &Self) -> bool {
92        self.info.bundle.id == other.info.bundle.id
93            && self.info.bundle.version == other.info.bundle.version
94    }
95}
96
97impl<O: Send + Sync, I: Info, ID: AsRef<str>> PartialEq<(ID, &Version)> for Plugin<'_, O, I> {
98    fn eq(&self, (id, version): &(ID, &Version)) -> bool {
99        self.info.bundle.id == *id.as_ref() && self.info.bundle.version == **version
100    }
101}
102
103impl<O: Send + Sync, I: Info> PartialEq<Bundle> for Plugin<'_, O, I> {
104    fn eq(&self, Bundle { id, version, .. }: &Bundle) -> bool {
105        self.info.bundle.id == *id && self.info.bundle.version == *version
106    }
107}
108
109impl<O: Send + Sync, I: Info> PartialEq<Depend> for Plugin<'_, O, I> {
110    fn eq(&self, Depend { id: name, version }: &Depend) -> bool {
111        self.info.bundle.id == *name && version.matches(&self.info.bundle.version)
112    }
113}
114
115impl<O: Send + Sync, I: Info> Eq for Plugin<'_, O, I> {}
116
117impl<O: Send + Sync, I: Info> PartialOrd for Plugin<'_, O, I> {
118    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
119        match self.info.bundle.id == other.info.bundle.id {
120            true => self
121                .info
122                .bundle
123                .version
124                .partial_cmp(&other.info.bundle.version),
125            false => None,
126        }
127    }
128}
129
130impl<O: Send + Sync, I: Info, ID: AsRef<str>> PartialOrd<(ID, &Version)> for Plugin<'_, O, I> {
131    fn partial_cmp(&self, (id, version): &(ID, &Version)) -> Option<Ordering> {
132        match self.info.bundle.id == *id.as_ref() {
133            true => self.info.bundle.version.partial_cmp(*version),
134            false => None,
135        }
136    }
137}
138
139impl<O: Send + Sync, I: Info> PartialOrd<Bundle> for Plugin<'_, O, I> {
140    fn partial_cmp(&self, Bundle { id, version, .. }: &Bundle) -> Option<Ordering> {
141        match self.info.bundle.id == *id {
142            true => self.info.bundle.version.partial_cmp(version),
143            false => None,
144        }
145    }
146}
147
148impl<O: Send + Sync, I: Info> Debug for Plugin<'_, O, I> {
149    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
150        f.debug_struct("Plugin")
151            .field("id", &self.info.bundle.id)
152            .field("version", &self.info.bundle.version)
153            .field("format", &self.info.bundle.format)
154            .field("path", &self.info.path)
155            .field("is_load", &self.is_load)
156            .field("depends", self.info.info.depends())
157            .field("optional_depends", self.info.info.optional_depends())
158            .finish()
159    }
160}