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}