vapoursynth/vsscript/
environment.rs1use std::ffi::{CStr, CString};
2use std::ops::{Deref, DerefMut};
3use std::path::Path;
4use std::ptr;
5use std::ptr::NonNull;
6use vapoursynth_sys as ffi;
7
8use crate::api::API;
9use crate::core::CoreRef;
10use crate::map::Map;
11use crate::node::Node;
12use crate::vsscript::errors::Result;
13use crate::vsscript::*;
14
15use crate::vsscript::VSScriptError;
16
17#[derive(Debug, Clone, Copy, Eq, PartialEq)]
19pub enum EvalFlags {
20 Nothing,
21 SetWorkingDir,
23}
24
25#[derive(Clone, Copy)]
27enum EvaluateScriptArgs<'a> {
28 Script(&'a str),
30 File(&'a Path, EvalFlags),
32}
33
34#[derive(Debug)]
36pub struct Environment {
37 handle: NonNull<ffi::VSScript>,
38}
39
40unsafe impl Send for Environment {}
41unsafe impl Sync for Environment {}
42
43impl Drop for Environment {
44 #[inline]
45 fn drop(&mut self) {
46 let api = VSScriptAPI::get().expect("VSScript API not available");
47 unsafe {
48 (api.handle().freeScript.unwrap())(self.handle.as_ptr());
49 }
50 }
51}
52
53impl Environment {
54 #[inline]
59 unsafe fn error(&self) -> CString {
60 let api = VSScriptAPI::get().expect("VSScript API not available");
61 let message = (api.handle().getError.unwrap())(self.handle.as_ptr());
62 CStr::from_ptr(message).to_owned()
63 }
64
65 pub fn new() -> Result<Self> {
70 let api = VSScriptAPI::get().expect("VSScript API not available");
71 let handle = unsafe { (api.handle().createScript.unwrap())(ptr::null_mut()) };
72
73 if handle.is_null() {
74 Err(Error::ScriptCreationFailed)
75 } else {
76 Ok(Self {
77 handle: unsafe { NonNull::new_unchecked(handle) },
78 })
79 }
80 }
81
82 fn evaluate_script(&mut self, args: EvaluateScriptArgs) -> Result<()> {
89 let api = VSScriptAPI::get().expect("VSScript API not available");
90
91 let rv = match args {
92 EvaluateScriptArgs::Script(script) => {
93 let script = CString::new(script)?;
94 let filename = CString::new("<string>").unwrap();
95 unsafe {
96 (api.handle().evaluateBuffer.unwrap())(
97 self.handle.as_ptr(),
98 script.as_ptr(),
99 filename.as_ptr(),
100 )
101 }
102 }
103 EvaluateScriptArgs::File(path, flags) => {
104 if flags == EvalFlags::SetWorkingDir {
106 unsafe {
107 (api.handle().evalSetWorkingDir.unwrap())(self.handle.as_ptr(), 1);
108 }
109 }
110
111 let path_str = path.to_str().ok_or(Error::PathInvalidUnicode)?;
113 let path_cstr = CString::new(path_str)?;
114
115 let rv = unsafe {
116 (api.handle().evaluateFile.unwrap())(self.handle.as_ptr(), path_cstr.as_ptr())
117 };
118
119 if flags == EvalFlags::SetWorkingDir {
121 unsafe {
122 (api.handle().evalSetWorkingDir.unwrap())(self.handle.as_ptr(), 0);
123 }
124 }
125
126 rv
127 }
128 };
129
130 if rv != 0 {
131 Err(VSScriptError::new(unsafe { self.error() }).into())
132 } else {
133 Ok(())
134 }
135 }
136
137 #[inline]
139 pub fn from_script(script: &str) -> Result<Self> {
140 let mut environment = Self::new()?;
141 environment.evaluate_script(EvaluateScriptArgs::Script(script))?;
142 Ok(environment)
143 }
144
145 #[inline]
147 pub fn from_file<P: AsRef<Path>>(path: P, flags: EvalFlags) -> Result<Self> {
148 let mut environment = Self::new()?;
149 environment.evaluate_script(EvaluateScriptArgs::File(path.as_ref(), flags))?;
150 Ok(environment)
151 }
152
153 #[inline]
155 pub fn eval_script(&mut self, script: &str) -> Result<()> {
156 self.evaluate_script(EvaluateScriptArgs::Script(script))
157 }
158
159 #[inline]
161 pub fn eval_file<P: AsRef<Path>>(&mut self, path: P, flags: EvalFlags) -> Result<()> {
162 self.evaluate_script(EvaluateScriptArgs::File(path.as_ref(), flags))
163 }
164
165 #[inline]
170 pub fn clear(&self) {
171 }
174
175 #[inline]
178 pub fn get_output(&self, index: i32) -> Result<(Node<'_>, Option<Node<'_>>)> {
179 API::get().ok_or(Error::NoAPI)?;
181
182 let vsscript_api = VSScriptAPI::get().expect("VSScript API not available");
183 let node_handle =
184 unsafe { (vsscript_api.handle().getOutputNode.unwrap())(self.handle.as_ptr(), index) };
185
186 if node_handle.is_null() {
187 return Err(Error::NoOutput);
188 }
189
190 let node = unsafe { Node::from_ptr(node_handle) };
191
192 let alpha_handle = unsafe {
194 (vsscript_api.handle().getOutputAlphaNode.unwrap())(self.handle.as_ptr(), index)
195 };
196 let alpha_node = if alpha_handle.is_null() {
197 None
198 } else {
199 Some(unsafe { Node::from_ptr(alpha_handle) })
200 };
201
202 Ok((node, alpha_node))
203 }
204
205 #[inline]
210 pub fn clear_output(&self, _index: i32) -> Result<()> {
211 Ok(())
213 }
214
215 pub fn get_core(&self) -> Result<CoreRef<'_>> {
218 API::get().ok_or(Error::NoAPI)?;
220
221 let vsscript_api = VSScriptAPI::get().expect("VSScript API not available");
222 let ptr = unsafe { (vsscript_api.handle().getCore.unwrap())(self.handle.as_ptr()) };
223 if ptr.is_null() {
224 Err(Error::NoCore)
225 } else {
226 Ok(unsafe { CoreRef::from_ptr(ptr) })
227 }
228 }
229
230 pub fn get_variable(&self, name: &str, map: &mut Map) -> Result<()> {
232 let vsscript_api = VSScriptAPI::get().expect("VSScript API not available");
233 let name = CString::new(name)?;
234 let rv = unsafe {
235 (vsscript_api.handle().getVariable.unwrap())(
236 self.handle.as_ptr(),
237 name.as_ptr(),
238 map.deref_mut(),
239 )
240 };
241 if rv != 0 {
242 Err(Error::NoSuchVariable)
243 } else {
244 Ok(())
245 }
246 }
247
248 pub fn set_variables(&self, variables: &Map) -> Result<()> {
250 let vsscript_api = VSScriptAPI::get().expect("VSScript API not available");
251 let rv = unsafe {
252 (vsscript_api.handle().setVariables.unwrap())(self.handle.as_ptr(), variables.deref())
253 };
254 if rv != 0 {
255 Err(Error::NoSuchVariable)
256 } else {
257 Ok(())
258 }
259 }
260
261 #[inline]
266 pub fn clear_variable(&self, _name: &str) -> Result<()> {
267 Ok(())
269 }
270}