diff --git a/src/sdl2/audio.rs b/src/sdl2/audio.rs index a519fa50..5b32f91f 100644 --- a/src/sdl2/audio.rs +++ b/src/sdl2/audio.rs @@ -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 { - let ops = try!(RWops::from_file(path, "rb")); - AudioSpecWAV::load_wav_rw(&ops) + /// Loads a WAVE from the file path. + pub fn load_wav>(path: P) -> SdlResult { + 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 { + /// Loads a WAVE from the data source. + pub fn load_wav_rw(src: &mut RWops) -> SdlResult { use std::mem::uninitialized; use std::ptr::null_mut; diff --git a/src/sdl2/rwops.rs b/src/sdl2/rwops.rs index 51ac46f8..9348f79b 100644 --- a/src/sdl2/rwops.rs +++ b/src/sdl2/rwops.rs @@ -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 { - 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 { + /// Creates an SDL file stream. + pub fn from_file>(path: P, mode: &str) -> SdlResult> { + 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> { 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> { + 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 { + 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 { 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 { 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 { // whence code is different from SeekStyle let (whence, offset) = match pos { diff --git a/src/sdl2/surface.rs b/src/sdl2/surface.rs index 12ef1b71..dceafe81 100644 --- a/src/sdl2/surface.rs +++ b/src/sdl2/surface.rs @@ -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> { + pub fn load_bmp_rw(rwops: &mut RWops) -> SdlResult> { 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>(path: P) -> SdlResult> { + let mut file = try!(RWops::from_file(path, "rb")); + Surface::load_bmp_rw(&mut file) + } + + pub fn save_bmp>(&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 diff --git a/tests/lib.rs b/tests/lib.rs index e9894333..7f4df1ed 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -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);