mirror of
https://github.com/encounter/rust-sdl2.git
synced 2026-07-10 21:18:41 -07:00
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:
+6
-6
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user