util/dictionary: refactor and make more sound
This commit is contained in:
@ -1,153 +0,0 @@
|
||||
use std::marker::PhantomData;
|
||||
use std::ptr;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::str::from_utf8_unchecked;
|
||||
|
||||
use ffi::*;
|
||||
|
||||
pub struct Dictionary<'a> {
|
||||
ptr: *mut AVDictionary,
|
||||
|
||||
_own: bool,
|
||||
_marker: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
impl<'a> Dictionary<'a> {
|
||||
pub unsafe fn wrap(ptr: *mut AVDictionary) -> Self {
|
||||
Dictionary { ptr: ptr, _own: false, _marker: PhantomData }
|
||||
}
|
||||
|
||||
pub unsafe fn own(ptr: *mut AVDictionary) -> Self {
|
||||
Dictionary { ptr: ptr, _own: true, _marker: PhantomData }
|
||||
}
|
||||
|
||||
pub unsafe fn as_ptr(&self) -> *const AVDictionary {
|
||||
self.ptr as *const _
|
||||
}
|
||||
|
||||
pub unsafe fn as_mut_ptr(&mut self) -> *mut AVDictionary {
|
||||
self.ptr
|
||||
}
|
||||
|
||||
pub unsafe fn take(mut self) -> *mut AVDictionary {
|
||||
self._own = false;
|
||||
self.ptr
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Dictionary<'a> {
|
||||
pub fn new() -> Self {
|
||||
Dictionary { ptr: ptr::null_mut(), _own: true, _marker: PhantomData }
|
||||
}
|
||||
|
||||
pub fn set(&mut self, key: &str, value: &str) {
|
||||
unsafe {
|
||||
let key = CString::new(key).unwrap();
|
||||
let value = CString::new(value).unwrap();
|
||||
let mut ptr = self.as_mut_ptr();
|
||||
|
||||
if av_dict_set(&mut ptr, key.as_ptr(), value.as_ptr(), 0) < 0 {
|
||||
panic!("out of memory");
|
||||
}
|
||||
|
||||
self.ptr = ptr;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&'a self, key: &str) -> Option<&'a str> {
|
||||
unsafe {
|
||||
let key = CString::new(key).unwrap();
|
||||
let entry = av_dict_get(self.as_ptr(), key.as_ptr(), ptr::null_mut(), 0);
|
||||
|
||||
if entry.is_null() {
|
||||
None
|
||||
}
|
||||
else {
|
||||
Some(from_utf8_unchecked(CStr::from_ptr((*entry).value).to_bytes()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> DictionaryIter {
|
||||
unsafe {
|
||||
DictionaryIter::new(self.as_ptr())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Clone for Dictionary<'a> {
|
||||
fn clone(&self) -> Self {
|
||||
let mut dictionary = Dictionary::new();
|
||||
dictionary.clone_from(self);
|
||||
|
||||
dictionary
|
||||
}
|
||||
|
||||
fn clone_from(&mut self, source: &Self) {
|
||||
unsafe {
|
||||
let mut ptr = self.as_mut_ptr();
|
||||
av_dict_copy(&mut ptr, source.as_ptr(), 0);
|
||||
self.ptr = ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a Dictionary<'a> {
|
||||
type Item = (&'a str, &'a str);
|
||||
type IntoIter = DictionaryIter<'a>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for Dictionary<'a> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if self._own && self.as_ptr() != ptr::null() {
|
||||
av_dict_free(&mut self.as_mut_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DictionaryIter<'a> {
|
||||
ptr: *const AVDictionary,
|
||||
cur: *mut AVDictionaryEntry,
|
||||
|
||||
_marker: PhantomData<&'a Dictionary<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> DictionaryIter<'a> {
|
||||
pub fn new(dictionary: *const AVDictionary) -> Self {
|
||||
DictionaryIter {
|
||||
ptr: dictionary,
|
||||
cur: ptr::null_mut(),
|
||||
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for DictionaryIter<'a> {
|
||||
type Item = (&'a str, &'a str);
|
||||
|
||||
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
|
||||
unsafe {
|
||||
let empty = CString::new("").unwrap();
|
||||
let entry = av_dict_get(self.ptr, empty.as_ptr(), self.cur, AV_DICT_IGNORE_SUFFIX);
|
||||
|
||||
if !entry.is_null() {
|
||||
let key = from_utf8_unchecked(CStr::from_ptr((*entry).key).to_bytes());
|
||||
let val = from_utf8_unchecked(CStr::from_ptr((*entry).value).to_bytes());
|
||||
|
||||
self.cur = entry;
|
||||
|
||||
Some((key, val))
|
||||
}
|
||||
else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
58
src/util/dictionary/immutable.rs
Normal file
58
src/util/dictionary/immutable.rs
Normal file
@ -0,0 +1,58 @@
|
||||
use std::marker::PhantomData;
|
||||
use std::ptr;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::str::from_utf8_unchecked;
|
||||
|
||||
use ffi::*;
|
||||
use super::{Iter, Owned};
|
||||
|
||||
pub struct Ref<'a> {
|
||||
ptr: *const AVDictionary,
|
||||
|
||||
_marker: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
impl<'a> Ref<'a> {
|
||||
pub unsafe fn wrap(ptr: *const AVDictionary) -> Self {
|
||||
Ref { ptr: ptr, _marker: PhantomData }
|
||||
}
|
||||
|
||||
pub unsafe fn as_ptr(&self) -> *const AVDictionary {
|
||||
self.ptr
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Ref<'a> {
|
||||
pub fn get(&'a self, key: &str) -> Option<&'a str> {
|
||||
unsafe {
|
||||
let key = CString::new(key).unwrap();
|
||||
let entry = av_dict_get(self.as_ptr(), key.as_ptr(), ptr::null_mut(), 0);
|
||||
|
||||
if entry.is_null() {
|
||||
None
|
||||
}
|
||||
else {
|
||||
Some(from_utf8_unchecked(CStr::from_ptr((*entry).value).to_bytes()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> Iter {
|
||||
unsafe {
|
||||
Iter::new(self.as_ptr())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_owned(&self) -> Owned {
|
||||
self.iter().collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a Ref<'a> {
|
||||
type Item = (&'a str, &'a str);
|
||||
type IntoIter = Iter<'a>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter()
|
||||
}
|
||||
}
|
47
src/util/dictionary/iter.rs
Normal file
47
src/util/dictionary/iter.rs
Normal file
@ -0,0 +1,47 @@
|
||||
use std::marker::PhantomData;
|
||||
use std::ptr;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::str::from_utf8_unchecked;
|
||||
|
||||
use ffi::*;
|
||||
|
||||
pub struct Iter<'a> {
|
||||
ptr: *const AVDictionary,
|
||||
cur: *mut AVDictionaryEntry,
|
||||
|
||||
_marker: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
impl<'a> Iter<'a> {
|
||||
pub fn new(dictionary: *const AVDictionary) -> Self {
|
||||
Iter {
|
||||
ptr: dictionary,
|
||||
cur: ptr::null_mut(),
|
||||
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Iter<'a> {
|
||||
type Item = (&'a str, &'a str);
|
||||
|
||||
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
|
||||
unsafe {
|
||||
let empty = CString::new("").unwrap();
|
||||
let entry = av_dict_get(self.ptr, empty.as_ptr(), self.cur, AV_DICT_IGNORE_SUFFIX);
|
||||
|
||||
if !entry.is_null() {
|
||||
let key = from_utf8_unchecked(CStr::from_ptr((*entry).key).to_bytes());
|
||||
let val = from_utf8_unchecked(CStr::from_ptr((*entry).value).to_bytes());
|
||||
|
||||
self.cur = entry;
|
||||
|
||||
Some((key, val))
|
||||
}
|
||||
else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
src/util/dictionary/mod.rs
Normal file
11
src/util/dictionary/mod.rs
Normal file
@ -0,0 +1,11 @@
|
||||
mod immutable;
|
||||
pub use self::immutable::Ref;
|
||||
|
||||
mod mutable;
|
||||
pub use self::mutable::Ref as Mut;
|
||||
|
||||
mod owned;
|
||||
pub use self::owned::Owned;
|
||||
|
||||
mod iter;
|
||||
pub use self::iter::Iter;
|
47
src/util/dictionary/mutable.rs
Normal file
47
src/util/dictionary/mutable.rs
Normal file
@ -0,0 +1,47 @@
|
||||
use std::ops::Deref;
|
||||
use std::marker::PhantomData;
|
||||
use std::ffi::CString;
|
||||
|
||||
use ffi::*;
|
||||
use super::immutable;
|
||||
|
||||
pub struct Ref<'a> {
|
||||
ptr: *mut AVDictionary,
|
||||
imm: immutable::Ref<'a>,
|
||||
|
||||
_marker: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
impl<'a> Ref<'a> {
|
||||
pub unsafe fn wrap(ptr: *mut AVDictionary) -> Self {
|
||||
Ref { ptr: ptr, imm: immutable::Ref::wrap(ptr), _marker: PhantomData }
|
||||
}
|
||||
|
||||
pub unsafe fn as_mut_ptr(&self) -> *mut AVDictionary {
|
||||
self.ptr
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Ref<'a> {
|
||||
pub fn set(&mut self, key: &str, value: &str) {
|
||||
unsafe {
|
||||
let key = CString::new(key).unwrap();
|
||||
let value = CString::new(value).unwrap();
|
||||
let mut ptr = self.as_mut_ptr();
|
||||
|
||||
if av_dict_set(&mut ptr, key.as_ptr(), value.as_ptr(), 0) < 0 {
|
||||
panic!("out of memory");
|
||||
}
|
||||
|
||||
self.ptr = ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deref for Ref<'a> {
|
||||
type Target = immutable::Ref<'a>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.imm
|
||||
}
|
||||
}
|
82
src/util/dictionary/owned.rs
Normal file
82
src/util/dictionary/owned.rs
Normal file
@ -0,0 +1,82 @@
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::iter::FromIterator;
|
||||
use std::ptr;
|
||||
|
||||
use ffi::*;
|
||||
use super::mutable;
|
||||
|
||||
pub struct Owned<'a> {
|
||||
inner: mutable::Ref<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Owned<'a> {
|
||||
pub unsafe fn own(ptr: *mut AVDictionary) -> Self {
|
||||
Owned { inner: mutable::Ref::wrap(ptr) }
|
||||
}
|
||||
|
||||
pub unsafe fn disown(mut self) -> *mut AVDictionary {
|
||||
let result = self.inner.as_mut_ptr();
|
||||
self.inner = mutable::Ref::wrap(ptr::null_mut());
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Owned<'a> {
|
||||
pub fn new() -> Self {
|
||||
unsafe {
|
||||
Owned { inner: mutable::Ref::wrap(ptr::null_mut()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> FromIterator<(&'b str, &'b str)> for Owned<'a> {
|
||||
fn from_iter<T: IntoIterator<Item=(&'b str, &'b str)>>(iterator: T) -> Self {
|
||||
let mut result = Owned::new();
|
||||
|
||||
for (key, value) in iterator {
|
||||
result.set(key, value);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deref for Owned<'a> {
|
||||
type Target = mutable::Ref<'a>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DerefMut for Owned<'a> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Clone for Owned<'a> {
|
||||
fn clone(&self) -> Self {
|
||||
let mut dictionary = Owned::new();
|
||||
dictionary.clone_from(self);
|
||||
|
||||
dictionary
|
||||
}
|
||||
|
||||
fn clone_from(&mut self, source: &Self) {
|
||||
unsafe {
|
||||
let mut ptr = self.as_mut_ptr();
|
||||
av_dict_copy(&mut ptr, source.as_ptr(), 0);
|
||||
self.inner = mutable::Ref::wrap(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for Owned<'a> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
av_dict_free(&mut self.inner.as_mut_ptr());
|
||||
}
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ pub use self::flag::Flags;
|
||||
|
||||
use libc::c_int;
|
||||
use ffi::*;
|
||||
use ::Dictionary;
|
||||
use ::{Dictionary, DictionaryRef};
|
||||
|
||||
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
|
||||
pub struct Packet {
|
||||
@ -106,15 +106,15 @@ impl Frame {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn metadata(&self) -> Dictionary {
|
||||
pub fn metadata(&self) -> DictionaryRef {
|
||||
unsafe {
|
||||
Dictionary::wrap(av_frame_get_metadata(self.as_ptr()))
|
||||
DictionaryRef::wrap(av_frame_get_metadata(self.as_ptr()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_metadata(&mut self, value: Dictionary) {
|
||||
unsafe {
|
||||
av_frame_set_metadata(self.as_mut_ptr(), value.take());
|
||||
av_frame_set_metadata(self.as_mut_ptr(), value.disown());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ use std::str::from_utf8_unchecked;
|
||||
|
||||
use ffi::*;
|
||||
use super::Frame;
|
||||
use ::Dictionary;
|
||||
use ::DictionaryRef;
|
||||
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
||||
pub enum Type {
|
||||
@ -108,9 +108,9 @@ impl<'a> SideData<'a> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn metadata(&self) -> Dictionary {
|
||||
pub fn metadata(&self) -> DictionaryRef {
|
||||
unsafe {
|
||||
Dictionary::wrap((*self.as_ptr()).metadata)
|
||||
DictionaryRef::wrap((*self.as_ptr()).metadata)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user