1use std::ffi::{CStr, CString, NulError};
4use std::fmt;
5use std::marker::PhantomData;
6use std::ptr::NonNull;
7use vapoursynth_sys as ffi;
8
9use crate::api::API;
10use crate::format::{ColorFamily, Format, FormatID, SampleType};
11use crate::plugin::Plugin;
12
13#[derive(Debug, Clone, Copy, Hash)]
15pub struct Info {
16 pub version_string: &'static str,
18
19 pub core_version: i32,
21
22 pub api_version: i32,
24
25 pub num_threads: usize,
27
28 pub max_framebuffer_size: u64,
31
32 pub used_framebuffer_size: u64,
34}
35
36#[derive(Debug, Clone, Copy)]
38pub struct CoreRef<'core> {
39 handle: NonNull<ffi::VSCore>,
40 _owner: PhantomData<&'core ()>,
41}
42
43unsafe impl<'core> Send for CoreRef<'core> {}
44unsafe impl<'core> Sync for CoreRef<'core> {}
45
46impl<'core> CoreRef<'core> {
47 #[inline]
52 pub(crate) unsafe fn from_ptr(handle: *mut ffi::VSCore) -> Self {
53 Self {
54 handle: NonNull::new_unchecked(handle),
55 _owner: PhantomData,
56 }
57 }
58
59 #[inline]
61 pub(crate) fn ptr(&self) -> *mut ffi::VSCore {
62 self.handle.as_ptr()
63 }
64
65 pub fn info(self) -> Info {
67 let raw_info = unsafe { &API::get_cached().get_core_info(self.handle.as_ptr()) };
68
69 let version_string = unsafe { CStr::from_ptr(raw_info.versionString).to_str().unwrap() };
70 debug_assert!(raw_info.numThreads >= 0);
71 debug_assert!(raw_info.maxFramebufferSize >= 0);
72 debug_assert!(raw_info.usedFramebufferSize >= 0);
73
74 Info {
75 version_string,
76 core_version: raw_info.core,
77 api_version: raw_info.api,
78 num_threads: raw_info.numThreads as usize,
79 max_framebuffer_size: raw_info.maxFramebufferSize as u64,
80 used_framebuffer_size: raw_info.usedFramebufferSize as u64,
81 }
82 }
83
84 #[inline]
87 pub fn get_format(&self, id: FormatID) -> Option<Format<'core>> {
88 let ptr = unsafe { API::get_cached().get_format_preset(id.0, self.handle.as_ptr()) };
89 unsafe { ptr.as_ref().map(|p| Format::from_ptr(p)) }
90 }
91
92 #[inline]
101 pub fn register_format(
102 &self,
103 color_family: ColorFamily,
104 sample_type: SampleType,
105 bits_per_sample: u8,
106 sub_sampling_w: u8,
107 sub_sampling_h: u8,
108 ) -> Option<Format<'core>> {
109 unsafe {
110 API::get_cached()
111 .register_format(
112 color_family.into(),
113 sample_type.into(),
114 i32::from(bits_per_sample),
115 i32::from(sub_sampling_w),
116 i32::from(sub_sampling_h),
117 self.handle.as_ptr(),
118 )
119 .as_ref()
120 .map(|p| Format::from_ptr(p))
121 }
122 }
123
124 #[inline]
126 pub fn get_plugin_by_id(&self, id: &str) -> Result<Option<Plugin<'core>>, NulError> {
127 let id = CString::new(id)?;
128 let ptr = unsafe { API::get_cached().get_plugin_by_id(id.as_ptr(), self.handle.as_ptr()) };
129 if ptr.is_null() {
130 Ok(None)
131 } else {
132 Ok(Some(unsafe { Plugin::from_ptr(ptr) }))
133 }
134 }
135
136 #[inline]
140 pub fn get_plugin_by_namespace(
141 &self,
142 namespace: &str,
143 ) -> Result<Option<Plugin<'core>>, NulError> {
144 let namespace = CString::new(namespace)?;
145 let ptr =
146 unsafe { API::get_cached().get_plugin_by_ns(namespace.as_ptr(), self.handle.as_ptr()) };
147 if ptr.is_null() {
148 Ok(None)
149 } else {
150 Ok(Some(unsafe { Plugin::from_ptr(ptr) }))
151 }
152 }
153
154 #[inline]
156 pub fn set_max_cache_size(&self, bytes: i64) -> i64 {
157 unsafe { API::get_cached().set_max_cache_size(bytes, self.handle.as_ptr()) }
158 }
159
160 #[inline]
167 pub fn set_thread_count(&self, threads: i32) -> i32 {
168 unsafe { API::get_cached().set_thread_count(threads, self.handle.as_ptr()) }
169 }
170}
171
172impl fmt::Display for Info {
173 #[inline]
174 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
175 write!(f, "{}", self.version_string)?;
176 writeln!(f, "Worker threads: {}", self.num_threads)?;
177 writeln!(
178 f,
179 "Max framebuffer cache size: {}",
180 self.max_framebuffer_size
181 )?;
182 writeln!(
183 f,
184 "Current framebuffer cache size: {}",
185 self.used_framebuffer_size
186 )
187 }
188}