Add lifetime to RWops, coerce Paths, update audio/surface RWops fns

* `SDL_RWFromConstMem` and `SDL_RWFromMem` only references the
  buffer, and never copies it - ergo, lifetime.
* `AsRef<Path>` lets us use ordinary string slices as path arguments,
  like in `std::fs::File`.
This commit is contained in:
Dan Spencer
2015-05-21 20:16:05 -06:00
parent 43d40f1d00
commit 83b945e9a9
4 changed files with 101 additions and 48 deletions
+6 -6
View File
@@ -208,14 +208,14 @@ pub struct AudioSpecWAV {
}
impl AudioSpecWAV {
/// Loads a WAVE from the file path. Uses `SDL_LoadWAV_RW`.
pub fn load_wav(path: &Path) -> SdlResult<AudioSpecWAV> {
let ops = try!(RWops::from_file(path, "rb"));
AudioSpecWAV::load_wav_rw(&ops)
/// Loads a WAVE from the file path.
pub fn load_wav<P: AsRef<Path>>(path: P) -> SdlResult<AudioSpecWAV> {
let mut file = try!(RWops::from_file(path, "rb"));
AudioSpecWAV::load_wav_rw(&mut file)
}
/// Loads a WAVE from the data source. Uses `SDL_LoadWAV_RW`.
pub fn load_wav_rw(src: &RWops) -> SdlResult<AudioSpecWAV> {
/// Loads a WAVE from the data source.
pub fn load_wav_rw(src: &mut RWops) -> SdlResult<AudioSpecWAV> {
use std::mem::uninitialized;
use std::ptr::null_mut;
+77 -32
View File
@@ -1,62 +1,107 @@
use std::ffi::CString;
use std::io;
use std::path::Path;
use std::marker::PhantomData;
use libc::{c_void, c_int, size_t};
use get_error;
use SdlResult;
use sys::rwops as ll;
#[derive(PartialEq)] #[allow(raw_pointer_derive)]
pub struct RWops {
/// A structure that provides an abstract interface to stream I/O.
pub struct RWops<'a> {
raw: *mut ll::SDL_RWops,
close_on_drop: bool
_marker: PhantomData<&'a ()>
}
impl_raw_accessors!((RWops, *mut ll::SDL_RWops));
impl_owned_accessors!((RWops, close_on_drop));
impl<'a> RWops<'a> {
pub unsafe fn raw(&self) -> *mut ll::SDL_RWops { self.raw }
/// A structure that provides an abstract interface to stream I/O.
impl RWops {
pub fn from_file(path: &Path, mode: &str) -> SdlResult<RWops> {
let raw = unsafe {
let path_c = CString::new(
path.as_os_str().to_str().unwrap()).unwrap().as_ptr();
let mode_c = CString::new(mode).unwrap().as_ptr();
ll::SDL_RWFromFile(path_c, mode_c)
};
if raw.is_null() { Err(get_error()) }
else { Ok(RWops{raw: raw, close_on_drop: true}) }
pub unsafe fn from_ll<'b>(raw: *mut ll::SDL_RWops) -> RWops<'b> {
RWops {
raw: raw,
_marker: PhantomData
}
}
pub fn from_bytes(buf: &[u8]) -> SdlResult<RWops> {
/// Creates an SDL file stream.
pub fn from_file<P: AsRef<Path>>(path: P, mode: &str) -> SdlResult<RWops<'static>> {
let raw = unsafe {
let path_c = CString::new(path.as_ref().to_str().unwrap()).unwrap();
let mode_c = CString::new(mode).unwrap();
ll::SDL_RWFromFile(path_c.as_ptr(), mode_c.as_ptr())
};
if raw.is_null() {
Err(get_error())
} else {
Ok(RWops {
raw: raw,
_marker: PhantomData
})
}
}
/// Prepares a read-only memory buffer for use with `RWops`.
///
/// This method can only fail if the buffer size is zero.
pub fn from_bytes(buf: &'a [u8]) -> SdlResult<RWops<'a>> {
let raw = unsafe {
ll::SDL_RWFromConstMem(buf.as_ptr() as *const c_void, buf.len() as c_int)
};
if raw.is_null() { Err(get_error()) }
else { Ok(RWops{raw: raw, close_on_drop: false}) }
if raw.is_null() {
Err(get_error())
} else {
Ok(RWops {
raw: raw,
_marker: PhantomData
})
}
}
pub fn len(&self) -> usize {
unsafe {
((*self.raw).size)(self.raw) as usize
/// Prepares a read-write memory buffer for use with `RWops`.
///
/// This method can only fail if the buffer size is zero.
pub fn from_bytes_mut(buf: &'a mut [u8]) -> SdlResult<RWops<'a>> {
let raw = unsafe {
ll::SDL_RWFromMem(buf.as_ptr() as *mut c_void, buf.len() as c_int)
};
if raw.is_null() {
Err(get_error())
} else {
Ok(RWops {
raw: raw,
_marker: PhantomData
})
}
}
/// Gets the stream's total size in bytes.
///
/// Returns `None` if the stream size can't be determined
/// (either because it doesn't make sense for the stream type, or there was an error).
pub fn len(&self) -> Option<usize> {
let result = unsafe { ((*self.raw).size)(self.raw) };
match result {
-1 => None,
v => Some(v as usize)
}
}
}
impl Drop for RWops {
impl<'a> Drop for RWops<'a> {
fn drop(&mut self) {
// TODO: handle close error
if self.close_on_drop {
let ret = unsafe { ((*self.raw).close)(self.raw) };
if ret != 0 {
println!("error {} when closing RWopt", get_error());
}
let ret = unsafe { ((*self.raw).close)(self.raw) };
if ret != 0 {
panic!(get_error());
}
}
}
impl io::Read for RWops {
impl<'a> io::Read for RWops<'a> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let out_len = buf.len() as size_t;
// FIXME: it's better to use as_mut_ptr().
@@ -68,7 +113,7 @@ impl io::Read for RWops {
}
}
impl io::Write for RWops {
impl<'a> io::Write for RWops<'a> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let in_len = buf.len() as size_t;
let ret = unsafe {
@@ -82,7 +127,7 @@ impl io::Write for RWops {
}
}
impl io::Seek for RWops {
impl<'a> io::Seek for RWops<'a> {
fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
// whence code is different from SeekStyle
let (whence, offset) = match pos {
+17 -7
View File
@@ -9,7 +9,7 @@ use libc::{c_int, uint32_t};
use num::FromPrimitive;
use pixels;
use render::BlendMode;
use rwops;
use rwops::RWops;
use sys::surface as ll;
@@ -171,9 +171,9 @@ impl<'a> Surface<'a> {
unsafe { ll::SDL_UnlockSurface(self.raw); }
}
pub fn from_bmp(path: &Path) -> SdlResult<Surface<'static>> {
pub fn load_bmp_rw(rwops: &mut RWops) -> SdlResult<Surface<'static>> {
let raw = unsafe {
ll::SDL_LoadBMP_RW(try!(rwops::RWops::from_file(path, "rb")).raw(), 0)
ll::SDL_LoadBMP_RW(rwops.raw(), 0)
};
if raw.is_null() {
@@ -187,14 +187,24 @@ impl<'a> Surface<'a> {
}
}
pub fn save_bmp(&self, path: &Path) -> SdlResult<()> {
let ret = unsafe {
ll::SDL_SaveBMP_RW(self.raw, try!(rwops::RWops::from_file(path, "rb")).raw(), 0)
};
pub fn save_bmp_rw(&self, rwops: &mut RWops) -> SdlResult<()> {
let ret = unsafe {
ll::SDL_SaveBMP_RW(self.raw, rwops.raw(), 0)
};
if ret == 0 { Ok(()) }
else { Err(get_error()) }
}
pub fn load_bmp<P: AsRef<Path>>(path: P) -> SdlResult<Surface<'static>> {
let mut file = try!(RWops::from_file(path, "rb"));
Surface::load_bmp_rw(&mut file)
}
pub fn save_bmp<P: AsRef<Path>>(&self, path: P) -> SdlResult<()> {
let mut file = try!(RWops::from_file(path, "wb"));
self.save_bmp_rw(&mut file)
}
pub fn set_palette(&self, palette: &pixels::Palette) -> bool {
unsafe {
ll::SDL_SetSurfacePalette(self.raw, palette.raw()) == 0
+1 -3
View File
@@ -1,10 +1,8 @@
extern crate sdl2;
use std::path::Path;
#[test]
fn audio_spec_wav() {
let wav = sdl2::audio::AudioSpecWAV::load_wav(&Path::new("./tests/sine.wav")).unwrap();
let wav = sdl2::audio::AudioSpecWAV::load_wav("./tests/sine.wav").unwrap();
assert_eq!(wav.freq, 22050);
assert_eq!(wav.format, sdl2::audio::AudioFormat::S16LSB);