use crate::error::{Result, Ret, RsmpegError};
use rusty_ffmpeg::ffi;
use std::{mem, ops::Deref, os::raw::c_int, ptr::NonNull, slice};
pub trait PointerUpgrade<T>: Sized {
fn upgrade(self) -> Option<NonNull<T>>;
}
impl<T> PointerUpgrade<T> for *const T {
#[inline]
fn upgrade(self) -> Option<NonNull<T>> {
NonNull::new(self as *mut _)
}
}
impl<T> PointerUpgrade<T> for *mut T {
#[inline]
fn upgrade(self) -> Option<NonNull<T>> {
NonNull::new(self)
}
}
#[allow(dead_code)]
pub trait RsmpegPointerUpgrade<T>: PointerUpgrade<T> {
fn upgrade_or(self, err: c_int) -> Result<NonNull<T>>;
}
impl<T> RsmpegPointerUpgrade<T> for *const T {
#[inline]
fn upgrade_or(self, err: c_int) -> Result<NonNull<T>> {
self.upgrade().ok_or(RsmpegError::AVError(err))
}
}
impl<T> RsmpegPointerUpgrade<T> for *mut T {
#[inline]
fn upgrade_or(self, err: c_int) -> Result<NonNull<T>> {
self.upgrade().ok_or(RsmpegError::AVError(err))
}
}
pub trait RetUpgrade {
fn upgrade(self) -> Ret;
}
impl RetUpgrade for c_int {
fn upgrade(self) -> Ret {
if self < 0 {
Ret::Err(self)
} else {
Ret::Ok(self)
}
}
}
pub trait UnsafeDerefMut: Deref {
unsafe fn deref_mut(&mut self) -> &mut Self::Target;
}
pub const AVERROR_EAGAIN: i32 = ffi::AVERROR(ffi::EAGAIN);
pub const AVERROR_ENOMEM: i32 = ffi::AVERROR(ffi::ENOMEM);
unsafe fn probe_len<T>(mut ptr: *const T, tail: T) -> usize {
for len in 0.. {
let left = ptr as *const u8;
let left = unsafe { slice::from_raw_parts(left, mem::size_of::<T>()) };
let right = &tail as *const _ as *const u8;
let right = unsafe { slice::from_raw_parts(right, mem::size_of::<T>()) };
if left == right {
return len;
}
unsafe {
ptr = ptr.add(1);
}
}
usize::MAX
}
pub unsafe fn build_array<'a, T>(ptr: *const T, tail: T) -> Option<&'a [T]> {
if ptr.is_null() {
None
} else {
let len = unsafe { probe_len(ptr, tail) };
Some(unsafe { slice::from_raw_parts(ptr, len) })
}
}