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

@ -55,7 +55,12 @@ impl Decoder {
pub fn open_as_with(mut self, codec: &Codec, options: Dictionary) -> Result<Opened, Error> {
unsafe {
if codec.is_decoder() {
match avcodec_open2(self.as_mut_ptr(), codec.as_ptr(), &mut options.take()) {
let mut opts = options.disown();
let res = avcodec_open2(self.as_mut_ptr(), codec.as_ptr(), &mut opts);
Dictionary::own(opts);
match res {
0 => Ok(Opened(self)),
e => Err(Error::from(e))
}

View File

@ -38,7 +38,12 @@ impl Audio {
pub fn open_as_with(mut self, codec: &Codec, options: Dictionary) -> Result<Encoder, Error> {
unsafe {
if codec.is_encoder() {
match avcodec_open2(self.as_mut_ptr(), codec.as_ptr(), &mut options.take()) {
let mut opts = options.disown();
let res = avcodec_open2(self.as_mut_ptr(), codec.as_ptr(), &mut opts);
Dictionary::own(opts);
match res {
0 => Ok(Encoder(self)),
e => Err(Error::from(e))
}

View File

@ -36,7 +36,12 @@ impl Subtitle {
pub fn open_as_with(mut self, codec: &Codec, options: Dictionary) -> Result<Encoder, Error> {
unsafe {
if codec.is_encoder() {
match avcodec_open2(self.as_mut_ptr(), codec.as_ptr(), &mut options.take()) {
let mut opts = options.disown();
let res = avcodec_open2(self.as_mut_ptr(), codec.as_ptr(), &mut opts);
Dictionary::own(opts);
match res {
0 => Ok(Encoder(self)),
e => Err(Error::from(e))
}

View File

@ -39,7 +39,12 @@ impl Video {
pub fn open_as_with(mut self, codec: &Codec, options: Dictionary) -> Result<Encoder, Error> {
unsafe {
if codec.is_encoder() {
match avcodec_open2(self.as_mut_ptr(), codec.as_ptr(), &mut options.take()) {
let mut opts = options.disown();
let res = avcodec_open2(self.as_mut_ptr(), codec.as_ptr(), &mut opts);
Dictionary::own(opts);
match res {
0 => Ok(Encoder(self)),
e => Err(Error::from(e))
}

View File

@ -3,7 +3,7 @@ use std::ptr;
use ffi::*;
use libc::{c_int, c_uint};
use ::{media, Stream, StreamMut, Dictionary};
use ::{media, Stream, StreamMut, DictionaryRef};
pub struct Context {
ptr: *mut AVFormatContext,
@ -60,9 +60,9 @@ impl Context {
}
}
pub fn metadata(&self) -> Dictionary {
pub fn metadata(&self) -> DictionaryRef {
unsafe {
Dictionary::wrap((*self.as_ptr()).metadata)
DictionaryRef::wrap((*self.as_ptr()).metadata)
}
}
}

View File

@ -39,12 +39,12 @@ impl Output {
pub fn write_header_with(&mut self, options: Dictionary) -> Result<(), Error> {
unsafe {
let mut opts = options.take();
let status = avformat_write_header(self.as_mut_ptr(), &mut opts);
let mut opts = options.disown();
let res = avformat_write_header(self.as_mut_ptr(), &mut opts);
Dictionary::own(opts);
match status {
match res {
0 => Ok(()),
e => Err(Error::from(e)),
}

View File

@ -100,14 +100,16 @@ pub fn open_with<P: AsRef<Path>>(path: &P, format: &Format, options: Dictionary)
unsafe {
let mut ps = ptr::null_mut();
let path = from_path(path);
let mut opts = options.take();
let mut opts = options.disown();
match format {
&Format::Input(ref format) => {
match avformat_open_input(&mut ps, path.as_ptr(), format.as_ptr(), &mut opts) {
0 => {
Dictionary::own(opts);
let res = avformat_open_input(&mut ps, path.as_ptr(), format.as_ptr(), &mut opts);
Dictionary::own(opts);
match res {
0 => {
match avformat_find_stream_info(ps, ptr::null_mut()) {
0 => Ok(Context::Input(context::Input::wrap(ps))),
e => Err(Error::from(e)),
@ -156,12 +158,13 @@ pub fn input_with<P: AsRef<Path>>(path: &P, options: Dictionary) -> Result<conte
unsafe {
let mut ps = ptr::null_mut();
let path = from_path(path);
let mut opts = options.take();
let mut opts = options.disown();
let res = avformat_open_input(&mut ps, path.as_ptr(), ptr::null_mut(), &mut opts);
match avformat_open_input(&mut ps, path.as_ptr(), ptr::null_mut(), &mut opts) {
Dictionary::own(opts);
match res {
0 => {
Dictionary::own(opts);
match avformat_find_stream_info(ps, ptr::null_mut()) {
0 => Ok(context::Input::wrap(ps)),
e => Err(Error::from(e))

View File

@ -9,7 +9,10 @@ pub use sys as ffi;
pub mod util;
pub use util::error::Error;
pub use util::dictionary::Dictionary;
pub use util::dictionary;
pub use util::dictionary::Owned as Dictionary;
pub use util::dictionary::Ref as DictionaryRef;
pub use util::dictionary::Mut as DictionaryMut;
pub use util::rational::{self, Rational};
pub use util::media;
pub use util::picture;

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