util/dictionary: refactor and make more sound

This commit is contained in:
meh
2015-09-08 18:26:29 +02:00
parent 620958d684
commit f2fb08e491
16 changed files with 297 additions and 179 deletions

View File

@ -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
}
}
}
}

View 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()
}
}

View 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
}
}
}
}

View 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;

View 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
}
}

View 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());
}
}
}

View File

@ -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());
}
}

View File

@ -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)
}
}
}