use rustsynth_sys as ffi;
use std::borrow::Cow;
use std::ffi::{c_int, CStr, CString};
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::ptr::NonNull;
use std::{result, slice};
use crate::api::API;
use crate::frame::{Frame, FrameRef};
use crate::function::Function;
use crate::node::Node;
mod errors;
pub use self::errors::{Error, InvalidKeyError, Result};
mod iterators;
pub use self::iterators::{Keys, ValueIter};
mod value;
pub use self::value::{Value, ValueNotArray, ValueType};
pub mod data;
pub use self::data::{handle_data_hint, Data, DataType};
#[derive(Debug)]
pub struct Map<'elem> {
handle: NonNull<ffi::VSMap>,
_elem: PhantomData<&'elem ()>,
}
#[derive(Debug)]
pub struct MapRef<'owner, 'elem> {
map: Map<'elem>,
_owner: PhantomData<&'owner ()>,
}
#[derive(Debug)]
pub struct MapRefMut<'owner, 'elem> {
map: Map<'elem>,
_owner: PhantomData<&'owner ()>,
}
#[derive(Debug)]
pub struct OwnedMap<'elem> {
map: Map<'elem>,
}
unsafe impl<'elem> Send for Map<'elem> {}
unsafe impl<'elem> Sync for Map<'elem> {}
#[doc(hidden)]
impl<'elem> Deref for Map<'elem> {
type Target = ffi::VSMap;
#[inline]
fn deref(&self) -> &Self::Target {
unsafe { self.handle.as_ref() }
}
}
#[doc(hidden)]
impl<'elem> DerefMut for Map<'elem> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.handle.as_mut() }
}
}
impl<'owner, 'elem> Deref for MapRef<'owner, 'elem> {
type Target = Map<'elem>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.map
}
}
impl<'owner, 'elem> Deref for MapRefMut<'owner, 'elem> {
type Target = Map<'elem>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.map
}
}
impl<'owner, 'elem> DerefMut for MapRefMut<'owner, 'elem> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.map
}
}
impl<'elem> Drop for OwnedMap<'elem> {
#[inline]
fn drop(&mut self) {
unsafe {
API::get_cached().free_map(&mut self.map);
}
}
}
impl<'elem> Deref for OwnedMap<'elem> {
type Target = Map<'elem>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.map
}
}
impl<'elem> DerefMut for OwnedMap<'elem> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.map
}
}
impl<'elem> OwnedMap<'elem> {
#[inline]
pub fn new() -> Self {
let api = API::get().unwrap();
Self {
map: unsafe { Map::from_ptr(api.create_map()) },
}
}
#[inline]
pub(crate) unsafe fn from_ptr(handle: *mut ffi::VSMap) -> Self {
Self {
map: Map::from_ptr(handle),
}
}
}
impl<'owner, 'elem> MapRef<'owner, 'elem> {
#[inline]
pub(crate) unsafe fn from_ptr(handle: *const ffi::VSMap) -> Self {
Self {
map: Map::from_ptr(handle),
_owner: PhantomData,
}
}
}
impl<'owner, 'elem> MapRefMut<'owner, 'elem> {
#[inline]
pub(crate) unsafe fn from_ptr(handle: *mut ffi::VSMap) -> Self {
Self {
map: Map::from_ptr(handle),
_owner: PhantomData,
}
}
}
#[inline]
fn handle_get_prop_error(error: i32) -> Result<()> {
if error == 0 {
Ok(())
} else {
Err(match error {
x if x == ffi::VSMapPropertyError::peUnset as i32 => Error::KeyNotFound,
x if x == ffi::VSMapPropertyError::peType as i32 => Error::WrongValueType,
x if x == ffi::VSMapPropertyError::peIndex as i32 => Error::IndexOutOfBounds,
x if x == ffi::VSMapPropertyError::peError as i32 => Error::Error,
_ => unreachable!(),
})
}
}
#[inline]
fn handle_append_prop_error(error: i32) -> Result<()> {
if error != 0 {
debug_assert!(error == 1);
Err(Error::WrongValueType)
} else {
Ok(())
}
}
impl<'elem> Default for OwnedMap<'elem> {
fn default() -> Self {
Self::new()
}
}
impl<'elem> Map<'elem> {
#[inline]
pub(crate) unsafe fn from_ptr(handle: *const ffi::VSMap) -> Self {
Self {
handle: NonNull::new_unchecked(handle as *mut ffi::VSMap),
_elem: PhantomData,
}
}
pub fn is_key_valid(key: &str) -> result::Result<(), InvalidKeyError> {
if key.is_empty() {
return Err(InvalidKeyError::EmptyKey);
}
let mut chars = key.chars();
let first = chars.next().unwrap();
if !first.is_ascii_alphabetic() && first != '_' {
return Err(InvalidKeyError::InvalidCharacter(0));
}
for (i, c) in chars.enumerate() {
if !c.is_ascii_alphanumeric() && c != '_' {
return Err(InvalidKeyError::InvalidCharacter(i + 1));
}
}
Ok(())
}
#[inline]
pub(crate) fn make_raw_key(key: &str) -> Result<CString> {
Map::is_key_valid(key)?;
Ok(CString::new(key).unwrap())
}
#[inline]
pub fn clear(&mut self) {
unsafe {
API::get_cached().clear_map(self);
}
}
#[inline]
pub fn error(&self) -> Option<Cow<str>> {
let error_message = unsafe { API::get_cached().map_get_error(self) };
if error_message.is_null() {
return None;
}
let error_message = unsafe { CStr::from_ptr(error_message) };
Some(error_message.to_string_lossy())
}
#[inline]
pub fn set_error(&mut self, error_message: &str) -> Result<()> {
let error_message = CString::new(error_message)?;
unsafe {
API::get_cached().map_set_error(self, error_message.as_ptr());
}
Ok(())
}
#[inline]
pub fn key_count(&self) -> usize {
let count = unsafe { API::get_cached().map_num_keys(self) };
debug_assert!(count >= 0);
count as usize
}
#[inline]
pub(crate) fn key_raw(&self, index: usize) -> &CStr {
assert!(index < self.key_count());
let index = index as i32;
unsafe { CStr::from_ptr(API::get_cached().map_get_key(self, index)) }
}
#[inline]
pub fn key(&self, index: usize) -> &str {
self.key_raw(index).to_str().unwrap()
}
#[inline]
pub fn keys(&self) -> Keys {
Keys::new(self)
}
#[inline]
pub(crate) unsafe fn value_count_raw_unchecked(&self, key: &CStr) -> Result<usize> {
let rv = API::get_cached().map_num_elements(self, key.as_ptr());
if rv == -1 {
Err(Error::KeyNotFound)
} else {
debug_assert!(rv >= 0);
Ok(rv as usize)
}
}
#[inline]
pub fn value_count(&self, key: &str) -> Result<usize> {
let key = Map::make_raw_key(key)?;
unsafe { self.value_count_raw_unchecked(&key) }
}
#[inline]
pub(crate) unsafe fn value_type_raw_unchecked(&self, key: &CStr) -> Result<ValueType> {
match API::get_cached().map_get_type(self, key.as_ptr()) {
x if x == ffi::VSPropertyType::ptUnset as c_int => Err(Error::KeyNotFound),
x if x == ffi::VSPropertyType::ptInt as c_int => Ok(ValueType::Int),
x if x == ffi::VSPropertyType::ptFloat as c_int => Ok(ValueType::Float),
x if x == ffi::VSPropertyType::ptData as c_int => Ok(ValueType::Data),
x if x
== ffi::VSPropertyType::ptVideoNode as c_int
| ffi::VSPropertyType::ptAudioNode as c_int =>
{
Ok(ValueType::Node)
}
x if x
== ffi::VSPropertyType::ptVideoFrame as c_int
| ffi::VSPropertyType::ptAudioFrame as c_int =>
{
Ok(ValueType::Frame)
}
x if x == ffi::VSPropertyType::ptFunction as c_int => Ok(ValueType::Function),
_ => unreachable!(),
}
}
#[inline]
pub fn value_type(&self, key: &str) -> Result<ValueType> {
let key = Map::make_raw_key(key)?;
unsafe { self.value_type_raw_unchecked(&key) }
}
#[inline]
pub(crate) unsafe fn delete_key_raw_unchecked(&mut self, key: &CStr) -> Result<()> {
let result = API::get_cached().map_delete_key(self, key.as_ptr());
if result == 0 {
Err(Error::KeyNotFound)
} else {
debug_assert!(result == 1);
Ok(())
}
}
#[inline]
pub fn delete_key(&mut self, key: &str) -> Result<()> {
let key = Map::make_raw_key(key)?;
unsafe { self.delete_key_raw_unchecked(&key) }
}
#[inline]
pub fn get<'map, T: Value<'map, 'elem> + Sized>(&'map self, key: &str) -> Result<T> {
T::get_from_map(self, key)
}
#[inline]
pub fn get_iter<'map, T: ValueNotArray<'map, 'elem>>(
&'map self,
key: &str,
) -> Result<ValueIter<'map, 'elem, T>> {
T::get_iter_from_map(self, key)
}
#[inline]
pub fn set<'map, T: Value<'map, 'elem>>(&'map mut self, key: &str, x: &T) -> Result<()> {
T::store_in_map(self, key, x)
}
#[inline]
pub fn append<'map, T: ValueNotArray<'map, 'elem>>(
&'map mut self,
key: &str,
x: &T,
) -> Result<()> {
T::append_to_map(self, key, x)
}
#[inline]
pub fn get_int(&self, key: &str) -> Result<i64> {
let key = Map::make_raw_key(key)?;
unsafe { self.get_int_raw_unchecked(&key, 0) }
}
#[inline]
pub fn get_int_iter<'map>(&'map self, key: &str) -> Result<ValueIter<'map, 'elem, i64>> {
let key = Map::make_raw_key(key)?;
unsafe { ValueIter::<i64>::new(self, key) }
}
#[inline]
pub fn get_float(&self, key: &str) -> Result<f64> {
let key = Map::make_raw_key(key)?;
unsafe { self.get_float_raw_unchecked(&key, 0) }
}
#[inline]
pub fn get_float_iter<'map>(&'map self, key: &str) -> Result<ValueIter<'map, 'elem, f64>> {
let key = Map::make_raw_key(key)?;
unsafe { ValueIter::<f64>::new(self, key) }
}
#[inline]
pub fn get_data(&self, key: &str) -> Result<Data<'elem>> {
let key = Map::make_raw_key(key)?;
unsafe { self.get_data_raw_unchecked(&key, 0) }
}
#[inline]
pub fn get_data_iter<'map>(
&'map self,
key: &str,
) -> Result<ValueIter<'map, 'elem, Data<'elem>>> {
let key = Map::make_raw_key(key)?;
unsafe { ValueIter::<Data>::new(self, key) }
}
#[inline]
pub fn get_string_iter<'map>(&'map self, key: &str) -> Result<ValueIter<'map, 'elem, String>> {
let key = Map::make_raw_key(key)?;
unsafe { ValueIter::<String>::new(self, key) }
}
#[inline]
pub(crate) unsafe fn get_string_raw_unchecked(&self, key: &CStr, index: i32) -> Result<String> {
let mut error = 0;
let value = API::get_cached().map_get_data(self, key.as_ptr(), index, &mut error);
handle_get_prop_error(error)?;
let mut error = 0;
let length = API::get_cached().map_get_data_size(self, key.as_ptr(), index, &mut error);
debug_assert!(error == 0);
debug_assert!(length >= 0);
let slice = slice::from_raw_parts(value as *const u8, length as usize);
Ok(String::from_utf8(slice.to_vec()).unwrap())
}
#[inline]
pub fn get_node(&self, key: &str) -> Result<Node<'elem>> {
let key = Map::make_raw_key(key)?;
unsafe { self.get_node_raw_unchecked(&key, 0) }
}
#[inline]
pub fn get_node_iter<'map>(
&'map self,
key: &str,
) -> Result<ValueIter<'map, 'elem, Node<'elem>>> {
let key = Map::make_raw_key(key)?;
unsafe { ValueIter::<Node>::new(self, key) }
}
#[inline]
pub fn get_frame(&self, key: &str) -> Result<FrameRef<'elem>> {
let key = Map::make_raw_key(key)?;
unsafe { self.get_frame_raw_unchecked(&key, 0) }
}
#[inline]
pub fn get_frame_iter<'map>(
&'map self,
key: &str,
) -> Result<ValueIter<'map, 'elem, FrameRef<'elem>>> {
let key = Map::make_raw_key(key)?;
unsafe { ValueIter::<FrameRef>::new(self, key) }
}
#[inline]
pub fn get_function(&self, key: &str) -> Result<Function<'elem>> {
let key = Map::make_raw_key(key)?;
unsafe { self.get_function_raw_unchecked(&key, 0) }
}
#[inline]
pub fn get_function_iter<'map>(
&'map self,
key: &str,
) -> Result<ValueIter<'map, 'elem, Function<'elem>>> {
let key = Map::make_raw_key(key)?;
unsafe { ValueIter::<Function>::new(self, key) }
}
#[inline]
pub fn get_int_array(&self, key: &str) -> Result<Vec<i64>> {
let key = Map::make_raw_key(key)?;
unsafe { self.get_int_array_raw_unchecked(&key) }
}
#[inline]
pub fn get_float_array(&self, key: &str) -> Result<Vec<f64>> {
let key = Map::make_raw_key(key)?;
unsafe { self.get_float_array_raw_unchecked(&key) }
}
#[inline]
pub(crate) unsafe fn get_int_raw_unchecked(&self, key: &CStr, index: i32) -> Result<i64> {
let mut error = 0;
let value = API::get_cached().map_get_int(self, key.as_ptr(), index, &mut error);
handle_get_prop_error(error)?;
Ok(value)
}
#[inline]
pub(crate) unsafe fn get_float_raw_unchecked(&self, key: &CStr, index: i32) -> Result<f64> {
let mut error = 0;
let value = API::get_cached().map_get_float(self, key.as_ptr(), index, &mut error);
handle_get_prop_error(error)?;
Ok(value)
}
#[inline]
pub(crate) unsafe fn get_data_raw_unchecked(
&self,
key: &CStr,
index: i32,
) -> Result<Data<'elem>> {
let mut error = 0;
let value = API::get_cached().map_get_data(self, key.as_ptr(), index, &mut error);
handle_get_prop_error(error)?;
let mut error = 0;
let length = API::get_cached().map_get_data_size(self, key.as_ptr(), index, &mut error);
debug_assert!(error == 0);
debug_assert!(length >= 0);
let slice = slice::from_raw_parts(value as *const u8, length as usize);
Ok(Data::from_slice(slice))
}
pub fn data_type_hint(&self, key: &CStr, index: i32) -> DataType {
let hint = unsafe {
API::get_cached().map_get_data_type_hint(self.handle.as_ptr(), key.as_ptr(), index)
};
handle_data_hint(hint)
}
#[inline]
pub(crate) unsafe fn get_node_raw_unchecked(
&self,
key: &CStr,
index: i32,
) -> Result<Node<'elem>> {
let mut error = 0;
let value = API::get_cached().map_get_node(self, key.as_ptr(), index, &mut error);
handle_get_prop_error(error)?;
Ok(Node::from_ptr(value))
}
#[inline]
pub(crate) unsafe fn get_int_array_raw_unchecked(&self, key: &CStr) -> Result<Vec<i64>> {
let mut error = 0;
let value = API::get_cached().map_get_int_array(self, key.as_ptr(), &mut error);
handle_get_prop_error(error)?;
Ok(slice::from_raw_parts(value, self.value_count_raw_unchecked(key).unwrap()).to_vec())
}
#[inline]
pub(crate) unsafe fn get_float_array_raw_unchecked(&self, key: &CStr) -> Result<Vec<f64>> {
let mut error = 0;
let value = API::get_cached().map_get_float_array(self, key.as_ptr(), &mut error);
handle_get_prop_error(error)?;
Ok(slice::from_raw_parts(value, self.value_count_raw_unchecked(key).unwrap()).to_vec())
}
#[inline]
pub(crate) unsafe fn get_frame_raw_unchecked(
&self,
key: &CStr,
index: i32,
) -> Result<FrameRef<'elem>> {
let mut error = 0;
let value = API::get_cached().map_get_frame(self, key.as_ptr(), index, &mut error);
handle_get_prop_error(error)?;
Ok(FrameRef::from_ptr(value))
}
#[inline]
pub(crate) unsafe fn get_function_raw_unchecked(
&self,
key: &CStr,
index: i32,
) -> Result<Function<'elem>> {
let mut error = 0;
let value = API::get_cached().map_get_func(self, key.as_ptr(), index, &mut error);
handle_get_prop_error(error)?;
Ok(Function::from_ptr(value))
}
#[inline]
pub fn append_int(&mut self, key: &str, x: i64) -> Result<()> {
let key = Map::make_raw_key(key)?;
unsafe { self.append_int_raw_unchecked(&key, x) }
}
#[inline]
pub fn append_float(&mut self, key: &str, x: f64) -> Result<()> {
let key = Map::make_raw_key(key)?;
unsafe { self.append_float_raw_unchecked(&key, x) }
}
#[inline]
pub fn append_data(&mut self, key: &str, x: &[u8]) -> Result<()> {
let key = Map::make_raw_key(key)?;
unsafe { self.append_data_raw_unchecked(&key, x) }
}
#[inline]
pub fn append_node(&mut self, key: &str, x: &Node<'elem>) -> Result<()> {
let key = Map::make_raw_key(key)?;
unsafe { self.append_node_raw_unchecked(&key, x) }
}
#[inline]
pub fn append_frame(&mut self, key: &str, x: &Frame<'elem>) -> Result<()> {
let key = Map::make_raw_key(key)?;
unsafe { self.append_frame_raw_unchecked(&key, x) }
}
#[inline]
pub fn append_function(&mut self, key: &str, x: &Function<'elem>) -> Result<()> {
let key = Map::make_raw_key(key)?;
unsafe { self.append_function_raw_unchecked(&key, x) }
}
#[inline]
pub(crate) unsafe fn append_int_raw_unchecked(&mut self, key: &CStr, x: i64) -> Result<()> {
let error =
API::get_cached().map_set_int(self, key.as_ptr(), x, ffi::VSMapAppendMode::maAppend);
handle_append_prop_error(error)
}
#[inline]
pub(crate) unsafe fn append_float_raw_unchecked(&mut self, key: &CStr, x: f64) -> Result<()> {
let error =
API::get_cached().map_set_float(self, key.as_ptr(), x, ffi::VSMapAppendMode::maAppend);
handle_append_prop_error(error)
}
#[inline]
pub(crate) unsafe fn append_data_raw_unchecked(&mut self, key: &CStr, x: &[u8]) -> Result<()> {
let error = API::get_cached().map_set_data(
self,
key.as_ptr(),
x,
ffi::VSDataTypeHint::dtUnknown,
ffi::VSMapAppendMode::maAppend,
);
handle_append_prop_error(error)
}
#[inline]
pub(crate) unsafe fn append_node_raw_unchecked(
&mut self,
key: &CStr,
x: &Node<'elem>,
) -> Result<()> {
let error = API::get_cached().map_set_node(
self,
key.as_ptr(),
x.ptr(),
ffi::VSMapAppendMode::maAppend,
);
handle_append_prop_error(error)
}
#[inline]
pub(crate) unsafe fn append_frame_raw_unchecked(
&mut self,
key: &CStr,
x: &Frame<'elem>,
) -> Result<()> {
let error = API::get_cached().map_set_frame(
self,
key.as_ptr(),
x.deref(),
ffi::VSMapAppendMode::maAppend,
);
handle_append_prop_error(error)
}
#[inline]
pub(crate) unsafe fn append_function_raw_unchecked(
&mut self,
key: &CStr,
x: &Function<'elem>,
) -> Result<()> {
let error = API::get_cached().map_set_func(
self,
key.as_ptr(),
x.ptr(),
ffi::VSMapAppendMode::maAppend,
);
handle_append_prop_error(error)
}
#[inline]
pub fn set_int(&mut self, key: &str, x: i64) -> Result<()> {
let key = Map::make_raw_key(key)?;
unsafe {
self.set_int_raw_unchecked(&key, x);
}
Ok(())
}
#[inline]
pub fn set_float(&mut self, key: &str, x: f64) -> Result<()> {
let key = Map::make_raw_key(key)?;
unsafe {
self.set_float_raw_unchecked(&key, x);
}
Ok(())
}
#[inline]
pub fn set_data(&mut self, key: &str, x: &[u8]) -> Result<()> {
let key = Map::make_raw_key(key)?;
unsafe {
self.set_data_raw_unchecked(&key, x);
}
Ok(())
}
#[inline]
pub fn set_node(&mut self, key: &str, x: &Node<'elem>) -> Result<()> {
let key = Map::make_raw_key(key)?;
unsafe {
self.set_node_raw_unchecked(&key, x);
}
Ok(())
}
#[inline]
pub fn set_frame(&mut self, key: &str, x: &Frame<'elem>) -> Result<()> {
let key = Map::make_raw_key(key)?;
unsafe {
self.set_frame_raw_unchecked(&key, x);
}
Ok(())
}
#[inline]
pub fn set_function(&mut self, key: &str, x: &Function<'elem>) -> Result<()> {
let key = Map::make_raw_key(key)?;
unsafe {
self.set_function_raw_unchecked(&key, x);
}
Ok(())
}
pub fn set_int_array(&mut self, key: &str, x: Vec<i64>) -> Result<()> {
let key = Map::make_raw_key(key)?;
unsafe {
self.set_int_array_raw_unchecked(&key, x);
}
Ok(())
}
pub fn set_float_array(&mut self, key: &str, x: Vec<f64>) -> Result<()> {
let key = Map::make_raw_key(key)?;
unsafe {
self.set_float_array_raw_unchecked(&key, x);
}
Ok(())
}
#[inline]
pub(crate) unsafe fn set_int_array_raw_unchecked(&mut self, key: &CStr, x: Vec<i64>) {
let error = API::get_cached().map_set_int_array(
self.handle.as_mut(),
key.as_ptr(),
x.as_ptr(),
x.len().try_into().unwrap(),
);
debug_assert!(error == 0);
}
#[inline]
pub(crate) unsafe fn set_float_array_raw_unchecked(&mut self, key: &CStr, x: Vec<f64>) {
let error = API::get_cached().map_set_float_array(
self.handle.as_mut(),
key.as_ptr(),
x.as_ptr(),
x.len().try_into().unwrap(),
);
debug_assert!(error == 0);
}
#[inline]
pub(crate) unsafe fn set_int_raw_unchecked(&mut self, key: &CStr, x: i64) {
let error =
API::get_cached().map_set_int(self, key.as_ptr(), x, ffi::VSMapAppendMode::maReplace);
debug_assert!(error == 0);
}
#[inline]
pub(crate) unsafe fn set_float_raw_unchecked(&mut self, key: &CStr, x: f64) {
let error =
API::get_cached().map_set_float(self, key.as_ptr(), x, ffi::VSMapAppendMode::maReplace);
debug_assert!(error == 0);
}
#[inline]
pub(crate) unsafe fn set_data_raw_unchecked(&mut self, key: &CStr, x: &[u8]) {
let error = API::get_cached().map_set_data(
self,
key.as_ptr(),
x,
ffi::VSDataTypeHint::dtUnknown,
ffi::VSMapAppendMode::maReplace,
);
debug_assert!(error == 0);
}
#[inline]
pub(crate) unsafe fn set_node_raw_unchecked(&mut self, key: &CStr, x: &Node<'elem>) {
let error = API::get_cached().map_set_node(
self,
key.as_ptr(),
x.ptr(),
ffi::VSMapAppendMode::maReplace,
);
debug_assert!(error == 0);
}
#[inline]
pub(crate) unsafe fn set_frame_raw_unchecked(&mut self, key: &CStr, x: &Frame<'elem>) {
let error = API::get_cached().map_set_frame(
self,
key.as_ptr(),
x.deref(),
ffi::VSMapAppendMode::maReplace,
);
debug_assert!(error == 0);
}
#[inline]
pub(crate) unsafe fn set_function_raw_unchecked(&mut self, key: &CStr, x: &Function<'elem>) {
let error = API::get_cached().map_set_func(
self,
key.as_ptr(),
x.ptr(),
ffi::VSMapAppendMode::maReplace,
);
debug_assert!(error == 0);
}
}