From f2fb08e4911723e32622306f014e5a355b064ac2 Mon Sep 17 00:00:00 2001 From: meh Date: Tue, 8 Sep 2015 18:26:29 +0200 Subject: [PATCH] util/dictionary: refactor and make more sound --- src/codec/decoder/mod.rs | 7 +- src/codec/encoder/audio.rs | 7 +- src/codec/encoder/subtitle.rs | 7 +- src/codec/encoder/video.rs | 7 +- src/format/context/common.rs | 6 +- src/format/context/output.rs | 6 +- src/format/mod.rs | 19 ++-- src/lib.rs | 5 +- src/util/dictionary.rs | 153 ------------------------------- src/util/dictionary/immutable.rs | 58 ++++++++++++ src/util/dictionary/iter.rs | 47 ++++++++++ src/util/dictionary/mod.rs | 11 +++ src/util/dictionary/mutable.rs | 47 ++++++++++ src/util/dictionary/owned.rs | 82 +++++++++++++++++ src/util/frame/mod.rs | 8 +- src/util/frame/side_data.rs | 6 +- 16 files changed, 297 insertions(+), 179 deletions(-) delete mode 100644 src/util/dictionary.rs create mode 100644 src/util/dictionary/immutable.rs create mode 100644 src/util/dictionary/iter.rs create mode 100644 src/util/dictionary/mod.rs create mode 100644 src/util/dictionary/mutable.rs create mode 100644 src/util/dictionary/owned.rs diff --git a/src/codec/decoder/mod.rs b/src/codec/decoder/mod.rs index 88603aa..95bc4b0 100644 --- a/src/codec/decoder/mod.rs +++ b/src/codec/decoder/mod.rs @@ -55,7 +55,12 @@ impl Decoder { pub fn open_as_with(mut self, codec: &Codec, options: Dictionary) -> Result { 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)) } diff --git a/src/codec/encoder/audio.rs b/src/codec/encoder/audio.rs index 4d3a31b..5279703 100644 --- a/src/codec/encoder/audio.rs +++ b/src/codec/encoder/audio.rs @@ -38,7 +38,12 @@ impl Audio { pub fn open_as_with(mut self, codec: &Codec, options: Dictionary) -> Result { 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)) } diff --git a/src/codec/encoder/subtitle.rs b/src/codec/encoder/subtitle.rs index d96547b..74cc57c 100644 --- a/src/codec/encoder/subtitle.rs +++ b/src/codec/encoder/subtitle.rs @@ -36,7 +36,12 @@ impl Subtitle { pub fn open_as_with(mut self, codec: &Codec, options: Dictionary) -> Result { 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)) } diff --git a/src/codec/encoder/video.rs b/src/codec/encoder/video.rs index 8eb7c8e..6a6faf7 100644 --- a/src/codec/encoder/video.rs +++ b/src/codec/encoder/video.rs @@ -39,7 +39,12 @@ impl Video { pub fn open_as_with(mut self, codec: &Codec, options: Dictionary) -> Result { 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)) } diff --git a/src/format/context/common.rs b/src/format/context/common.rs index 5f94667..4d8baea 100644 --- a/src/format/context/common.rs +++ b/src/format/context/common.rs @@ -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) } } } diff --git a/src/format/context/output.rs b/src/format/context/output.rs index 8005796..2cb576f 100644 --- a/src/format/context/output.rs +++ b/src/format/context/output.rs @@ -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)), } diff --git a/src/format/mod.rs b/src/format/mod.rs index 0d3f92b..f9143eb 100644 --- a/src/format/mod.rs +++ b/src/format/mod.rs @@ -100,14 +100,16 @@ pub fn open_with>(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>(path: &P, options: Dictionary) -> Result { - Dictionary::own(opts); - match avformat_find_stream_info(ps, ptr::null_mut()) { 0 => Ok(context::Input::wrap(ps)), e => Err(Error::from(e)) diff --git a/src/lib.rs b/src/lib.rs index e0e94f2..f2ab5d7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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; diff --git a/src/util/dictionary.rs b/src/util/dictionary.rs deleted file mode 100644 index 69dc400..0000000 --- a/src/util/dictionary.rs +++ /dev/null @@ -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<::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 - } - } - } -} diff --git a/src/util/dictionary/immutable.rs b/src/util/dictionary/immutable.rs new file mode 100644 index 0000000..84c9cee --- /dev/null +++ b/src/util/dictionary/immutable.rs @@ -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() + } +} diff --git a/src/util/dictionary/iter.rs b/src/util/dictionary/iter.rs new file mode 100644 index 0000000..42fee1a --- /dev/null +++ b/src/util/dictionary/iter.rs @@ -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<::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 + } + } + } +} diff --git a/src/util/dictionary/mod.rs b/src/util/dictionary/mod.rs new file mode 100644 index 0000000..60dec26 --- /dev/null +++ b/src/util/dictionary/mod.rs @@ -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; diff --git a/src/util/dictionary/mutable.rs b/src/util/dictionary/mutable.rs new file mode 100644 index 0000000..c6fc24a --- /dev/null +++ b/src/util/dictionary/mutable.rs @@ -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 + } +} diff --git a/src/util/dictionary/owned.rs b/src/util/dictionary/owned.rs new file mode 100644 index 0000000..313564b --- /dev/null +++ b/src/util/dictionary/owned.rs @@ -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>(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()); + } + } +} diff --git a/src/util/frame/mod.rs b/src/util/frame/mod.rs index 8443f13..632d126 100644 --- a/src/util/frame/mod.rs +++ b/src/util/frame/mod.rs @@ -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()); } } diff --git a/src/util/frame/side_data.rs b/src/util/frame/side_data.rs index 669ff63..9e16dde 100644 --- a/src/util/frame/side_data.rs +++ b/src/util/frame/side_data.rs @@ -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) } } }