1use bitflags::bitflags;
2use ffi::VSPluginFunction;
3use rustsynth_sys::{self as ffi, VSPluginConfigFlags};
4use std::{
5 ffi::{CStr, CString},
6 marker::PhantomData,
7 ops::Deref,
8 ptr::{self, NonNull},
9};
10
11use crate::{api::API, map::OwnedMap, prelude::Map};
12
13#[derive(Debug, Clone, Copy)]
17pub struct Plugin<'core> {
18 handle: NonNull<ffi::VSPlugin>,
19 _owner: PhantomData<&'core ()>,
20}
21
22unsafe impl<'core> Send for Plugin<'core> {}
23unsafe impl<'core> Sync for Plugin<'core> {}
24
25impl<'core> Plugin<'core> {
26 #[inline]
27 pub unsafe fn from_ptr(ptr: *mut ffi::VSPlugin) -> Self {
28 Plugin {
29 handle: NonNull::new_unchecked(ptr),
30 _owner: PhantomData,
31 }
32 }
33
34 #[inline]
36 pub(crate) fn ptr(&self) -> *mut ffi::VSPlugin {
37 self.handle.as_ptr()
38 }
39
40 pub fn path(&self) -> Option<String> {
42 let ptr = unsafe { API::get_cached().get_plugin_path(self.ptr()) };
43 if ptr.is_null() {
44 None
45 } else {
46 Some(unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() })
47 }
48 }
49
50 pub fn id(&self) -> Option<String> {
52 let ptr = unsafe { API::get_cached().get_plugin_id(self.ptr()) };
53 if ptr.is_null() {
54 None
55 } else {
56 Some(unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() })
57 }
58 }
59
60 pub fn namespace(&self) -> Option<String> {
62 let ptr = unsafe { API::get_cached().get_plugin_ns(self.ptr()) };
63 if ptr.is_null() {
64 None
65 } else {
66 Some(unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() })
67 }
68 }
69
70 pub fn name(&self) -> Option<String> {
72 let ptr = unsafe { API::get_cached().get_plugin_name(self.ptr()) };
73 if ptr.is_null() {
74 None
75 } else {
76 Some(unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() })
77 }
78 }
79
80 #[inline]
81 pub fn version(&self) -> i32 {
82 unsafe { API::get_cached().get_plugin_version(self.ptr()) }
83 }
84
85 pub fn function(&self, name: &str) -> Option<PluginFunction<'core>> {
89 let name_ptr = CString::new(name).unwrap();
90 unsafe {
91 let ptr = API::get_cached().get_plugin_function_by_name(name_ptr.as_ptr(), self.ptr());
92 if ptr.is_null() {
93 None
94 } else {
95 Some(PluginFunction::from_ptr(ptr))
96 }
97 }
98 }
99
100 pub fn functions(&'_ self) -> PluginFunctions<'_> {
102 PluginFunctions {
103 function: None,
104 plugin: self,
105 }
106 }
107
108 fn next_function(&self, function: Option<PluginFunction>) -> Option<PluginFunction<'core>> {
109 unsafe {
110 let function = if let Some(value) = function {
111 value.ptr()
112 } else {
113 ptr::null_mut()
114 };
115 let ptr = API::get_cached().get_next_plugin_function(function, self.ptr());
116 if ptr.is_null() {
117 None
118 } else {
119 Some(PluginFunction::from_ptr(ptr))
120 }
121 }
122 }
123
124 pub fn invoke(&self, name: &str, args: &Map<'core>) -> OwnedMap<'core> {
130 self.function(name).expect("No Plugin found");
131 let name = CString::new(name).unwrap();
132 unsafe {
133 OwnedMap::from_ptr(API::get_cached().invoke(
134 self.handle.as_ptr(),
135 name.as_ptr(),
136 args.deref(),
137 ))
138 }
139 }
140}
141
142bitflags! {
143 pub struct PluginConfigFlags: i32 {
144 const MODIFIABLE = 1;
146 const NONE = 0;
147 }
148}
149
150impl PluginConfigFlags {
151 pub fn as_ptr(&self) -> ffi::VSPluginConfigFlags {
152 VSPluginConfigFlags(self.bits.try_into().unwrap())
153 }
154}
155
156#[derive(Debug, Clone, Copy)]
160pub struct PluginFunctions<'core> {
161 function: Option<PluginFunction<'core>>,
162 plugin: &'core Plugin<'core>,
163}
164
165impl<'core> Iterator for PluginFunctions<'core> {
166 type Item = PluginFunction<'core>;
167
168 fn next(&mut self) -> Option<Self::Item> {
169 self.function = self.plugin.next_function(self.function);
170 self.function
171 }
172}
173
174#[derive(Debug, Clone, Copy)]
176pub struct PluginFunction<'core> {
177 ptr: NonNull<ffi::VSPluginFunction>,
178 pub name: Option<&'core str>,
179 pub arguments: Option<&'core str>,
180}
181
182impl<'core> PluginFunction<'core> {
183 pub(crate) unsafe fn from_ptr(ptr: *mut VSPluginFunction) -> Self {
184 let name_ptr = unsafe { API::get_cached().get_plugin_function_name(ptr) };
185 let name = if name_ptr.is_null() {
186 None
187 } else {
188 Some(unsafe { CStr::from_ptr(name_ptr).to_str().unwrap() })
189 };
190
191 let arg_ptr = unsafe { API::get_cached().get_plugin_function_arguments(ptr) };
192 let arguments = if arg_ptr.is_null() {
193 None
194 } else {
195 Some(unsafe { CStr::from_ptr(arg_ptr).to_str().unwrap() })
196 };
197 PluginFunction {
198 ptr: NonNull::new_unchecked(ptr),
199 name,
200 arguments,
201 }
202 }
203
204 fn ptr(&self) -> *mut ffi::VSPluginFunction {
205 self.ptr.as_ptr()
206 }
207}