Skip to content

Commit 93dde6b

Browse files
authored
Better errors (#173)
* Make errors more helpful in audio.rs * Finish audio errors * Add errors for data.rs * Add font and model errors * Add errors for texture.rs * Move error types into error.rs * Import texture error types * Add RaylibError type * Improve context of some errors
1 parent 4d53bd4 commit 93dde6b

File tree

6 files changed

+291
-188
lines changed

6 files changed

+291
-188
lines changed

raylib/src/core/audio.rs

Lines changed: 42 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
//! Contains code related to audio. [`RaylibAudio`] plays sounds and music.
22
3-
use crate::error::{error, Error};
4-
use crate::ffi;
5-
use std::ffi::CString;
3+
use crate::{ffi, error::{AudioInitError, LoadSoundError}};
4+
use std::ffi::{CStr, CString};
65
use std::marker::PhantomData;
76
use std::path::Path;
87

8+
use super::error::ExportWaveError;
9+
910
make_thin_wrapper_lifetime!(
1011
/// Wave, audio wave data
1112
Wave,
@@ -57,21 +58,6 @@ impl AudioSample for u8 {}
5758
impl AudioSample for i16 {}
5859
impl AudioSample for f32 {}
5960

60-
pub struct RaylibAudioInitError;
61-
62-
impl std::fmt::Debug for RaylibAudioInitError {
63-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64-
f.write_str("RaylibAudio cannot be instantiated more then once at a time.")
65-
}
66-
}
67-
impl std::fmt::Display for RaylibAudioInitError {
68-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69-
f.write_str("RaylibAudio cannot be instantiated more then once at a time.")
70-
}
71-
}
72-
73-
impl std::error::Error for RaylibAudioInitError {}
74-
7561
/// This token is used to indicate audio is initialized. It's also used to create [`Wave`], [`Sound`], [`Music`], [`AudioStream`], and [`SoundAlias`].
7662
/// All of those have a lifetime that is bound to RaylibAudio. The compiler will disallow you from using them without ensuring that the [`RaylibAudio`] is present while doing so.
7763
#[derive(Debug, Clone)]
@@ -80,12 +66,15 @@ pub struct RaylibAudio(PhantomData<()>);
8066
impl RaylibAudio {
8167
/// Initializes audio device and context.
8268
#[inline]
83-
pub fn init_audio_device() -> Result<RaylibAudio, RaylibAudioInitError> {
69+
pub fn init_audio_device() -> Result<RaylibAudio, AudioInitError> {
8470
unsafe {
8571
if ffi::IsAudioDeviceReady() {
86-
return Err(RaylibAudioInitError);
72+
return Err(AudioInitError::DoubleInit);
8773
}
8874
ffi::InitAudioDevice();
75+
if !ffi::IsAudioDeviceReady() {
76+
return Err(AudioInitError::InitFailed);
77+
}
8978
}
9079
Ok(RaylibAudio(PhantomData))
9180
}
@@ -118,32 +107,32 @@ impl RaylibAudio {
118107

119108
/// Loads a new sound from file.
120109
#[inline]
121-
pub fn new_sound<'aud>(&'aud self, filename: &str) -> Result<Sound<'aud>, Error> {
110+
pub fn new_sound<'aud>(&'aud self, filename: &str) -> Result<Sound<'aud>, LoadSoundError> {
122111
let c_filename = CString::new(filename).unwrap();
123112
let s = unsafe { ffi::LoadSound(c_filename.as_ptr()) };
124113
if s.stream.buffer.is_null() {
125-
return Err(error!("failed to load sound", filename));
114+
return Err(LoadSoundError::LoadFailed { path: filename.into() });
126115
}
127116

128117
Ok(Sound(s, self))
129118
}
130119

131120
/// Loads sound from wave data.
132121
#[inline]
133-
pub fn new_sound_from_wave<'aud>(&'aud self, wave: &Wave) -> Result<Sound<'aud>, Error> {
122+
pub fn new_sound_from_wave<'aud>(&'aud self, wave: &Wave) -> Result<Sound<'aud>, LoadSoundError> {
134123
let s = unsafe { ffi::LoadSoundFromWave(wave.0) };
135124
if s.stream.buffer.is_null() {
136-
return Err(error!("failed to load sound from wave"));
125+
return Err(LoadSoundError::LoadFromWaveFailed);
137126
}
138127
Ok(Sound(s, self))
139128
}
140129
/// Loads wave data from file into RAM.
141130
#[inline]
142-
pub fn new_wave<'aud>(&'aud self, filename: &str) -> Result<Wave<'aud>, Error> {
131+
pub fn new_wave<'aud>(&'aud self, filename: &str) -> Result<Wave<'aud>, LoadSoundError> {
143132
let c_filename = CString::new(filename).unwrap();
144133
let w = unsafe { ffi::LoadWave(c_filename.as_ptr()) };
145134
if w.data.is_null() {
146-
return Err(error!("Cannot load wave {}", filename));
135+
return Err(LoadSoundError::LoadWaveFromFileFailed { path: filename.into() });
147136
}
148137
Ok(Wave(w, self))
149138
}
@@ -154,24 +143,24 @@ impl RaylibAudio {
154143
&'aud self,
155144
filetype: &str,
156145
bytes: &[u8],
157-
) -> Result<Wave<'aud>, Error> {
146+
) -> Result<Wave<'aud>, LoadSoundError> {
158147
let c_filetype = CString::new(filetype).unwrap();
159148
let w = unsafe {
160149
ffi::LoadWaveFromMemory(c_filetype.as_ptr(), bytes.as_ptr(), bytes.len() as i32)
161150
};
162151
if w.data.is_null() {
163-
return Err(error!("Wave data is null. Check provided buffer data"));
152+
return Err(LoadSoundError::Null);
164153
};
165154
Ok(Wave(w, self))
166155
}
167156

168157
/// Loads music stream from file.
169158
#[inline]
170-
pub fn new_music<'aud>(&'aud self, filename: &str) -> Result<Music<'aud>, Error> {
159+
pub fn new_music<'aud>(&'aud self, filename: &str) -> Result<Music<'aud>, LoadSoundError> {
171160
let c_filename = CString::new(filename).unwrap();
172161
let m = unsafe { ffi::LoadMusicStream(c_filename.as_ptr()) };
173162
if m.stream.buffer.is_null() {
174-
return Err(error!("music could not be loaded from file", filename));
163+
return Err(LoadSoundError::LoadMusicFromFileFailed { path: filename.into() });
175164
}
176165
Ok(Music(m, self))
177166
}
@@ -182,15 +171,13 @@ impl RaylibAudio {
182171
&'aud self,
183172
filetype: &str,
184173
bytes: &Vec<u8>,
185-
) -> Result<Music<'aud>, Error> {
174+
) -> Result<Music<'aud>, LoadSoundError> {
186175
let c_filetype = CString::new(filetype).unwrap();
187176
let w = unsafe {
188177
ffi::LoadMusicStreamFromMemory(c_filetype.as_ptr(), bytes.as_ptr(), bytes.len() as i32)
189178
};
190179
if w.stream.buffer.is_null() {
191-
return Err(error!(
192-
"Music's buffer data data is null. Check provided buffer data"
193-
));
180+
return Err(LoadSoundError::MusicNull);
194181
};
195182
Ok(Music(w, self))
196183
}
@@ -253,9 +240,24 @@ impl<'aud> Wave<'aud> {
253240

254241
/// Export wave file. Extension must be .wav or .raw
255242
#[inline]
256-
pub fn export(&self, filename: impl AsRef<Path>) -> bool {
243+
pub fn export(&self, filename: impl AsRef<Path>) -> Result<(), ExportWaveError> {
257244
let c_filename = CString::new(filename.as_ref().to_string_lossy().as_bytes()).unwrap();
258-
unsafe { ffi::ExportWave(self.0, c_filename.as_ptr()) }
245+
let success = unsafe { ffi::ExportWave(self.0, c_filename.as_ptr()) };
246+
if success {
247+
Ok(())
248+
} else {
249+
// const WAV: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b".wav\0") };
250+
const QOA: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b".qoa\0") };
251+
// const RAW: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b".raw\0") };
252+
let is_qoa = unsafe { ffi::IsFileExtension(c_filename.as_ptr(), QOA.as_ptr()) };
253+
if is_qoa {
254+
let samples = self.0.sampleSize as i32;
255+
if samples != 16 {
256+
return Err(ExportWaveError::QoaBadSamples(self.0.sampleSize as i32));
257+
}
258+
}
259+
Err(ExportWaveError::ExportFailed)
260+
}
259261
}
260262

261263
/*/// Export wave sample data to code (.h)
@@ -650,10 +652,12 @@ impl<'aud> AudioStream<'aud> {
650652
}
651653

652654
impl<'bind> Sound<'bind> {
653-
pub fn alias<'snd>(&'snd self) -> Result<SoundAlias<'snd, 'bind>, Error> {
655+
/// Clone sound from existing sound data, clone does not own wave data
656+
// NOTE: Wave data must be unallocated manually and will be shared across all clones
657+
pub fn alias<'snd>(&'snd self) -> Result<SoundAlias<'snd, 'bind>, LoadSoundError> {
654658
let s = unsafe { ffi::LoadSoundAlias(self.0) };
655659
if s.stream.buffer.is_null() {
656-
return Err(error!("failed to load sound from wave"));
660+
return Err(LoadSoundError::LoadFromWaveFailed);
657661
}
658662
Ok(SoundAlias(s, PhantomData))
659663
}

raylib/src/core/data.rs

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@ use std::{
33
alloc::Layout, ffi::{c_char, CString}, ops::{Deref, DerefMut}, path::Path, ptr::NonNull
44
};
55

6-
use crate::{
7-
error::{error, Error},
8-
ffi,
9-
};
6+
use crate::{ffi, error::{AllocationError, CompressionError}};
107

118
/// A wrapper acting as an owned buffer for Raylib-allocated memory.
129
/// Automatically releases the memory with [`ffi::MemFree()`] when dropped.
@@ -115,22 +112,22 @@ impl<T: Copy> DataBuf<T> {
115112
/// # Panics
116113
///
117114
/// This method may panic if the pointer returned by [`ffi::MemAlloc`] is unaligned.
118-
pub fn alloc(count: i32) -> Result<Self, Error> {
115+
pub fn alloc(count: i32) -> Result<Self, AllocationError> {
119116
if count >= 1 {
120117
let count = count as usize;
121118
match Layout::array::<T>(count) {
122-
Err(_e) => Err(error!("memory request does not produce a valid layout")), // I would like to display `e` if possible
119+
Err(_e) => Err(AllocationError::InvalidLayout), // I would like to display `e` if possible
123120
Ok(layout) => {
124121
let size = layout.size();
125122
if size <= u32::MAX as usize {
126123
if let Some(buf) = NonNull::new(unsafe { ffi::MemAlloc(size as u32) }.cast()) {
127124
assert!(buf.is_aligned(), "allocated buffer should always be aligned");
128125
Ok(Self { buf, len: count })
129-
} else { Err(error!("memory request exceeds capacity")) }
130-
} else { Err(error!("memory request exceeds unsigned integer maximum")) }
126+
} else { Err(AllocationError::ExceedsCapacity) }
127+
} else { Err(AllocationError::ExceedsUIntMax) }
131128
}
132129
}
133-
} else { Err(error!("cannot allocate less than 1 element")) }
130+
} else { Err(AllocationError::SubMinSize) }
134131
}
135132

136133
/// Reallocate memory already managed by Raylib
@@ -146,11 +143,11 @@ impl<T: Copy> DataBuf<T> {
146143
/// # Panics
147144
///
148145
/// This method may panic if the pointer returned by [`ffi::MemRealloc`] is unaligned.
149-
pub fn realloc(&mut self, new_count: i32) -> Result<(), Error> {
146+
pub fn realloc(&mut self, new_count: i32) -> Result<(), AllocationError> {
150147
if new_count >= 1 {
151148
let new_count = new_count as usize;
152149
match Layout::array::<T>(new_count) {
153-
Err(_e) => Err(error!("memory request does not produce a valid layout")), // I would like to display `e` if possible
150+
Err(_e) => Err(AllocationError::InvalidLayout), // I would like to display `e` if possible
154151
Ok(layout) => {
155152
let size = layout.size();
156153
if size <= u32::MAX as usize {
@@ -159,11 +156,11 @@ impl<T: Copy> DataBuf<T> {
159156
self.buf = buf;
160157
self.len = new_count;
161158
Ok(())
162-
} else { Err(error!("memory request exceeds capacity")) }
163-
} else { Err(error!("memory request exceeds unsigned integer maximum")) }
159+
} else { Err(AllocationError::ExceedsCapacity) }
160+
} else { Err(AllocationError::ExceedsUIntMax) }
164161
}
165162
}
166-
} else { Err(error!("cannot allocate less than 1 element")) }
163+
} else { Err(AllocationError::SubMinSize) }
167164
}
168165
}
169166

@@ -174,14 +171,14 @@ impl<T: Copy> DataBuf<T> {
174171
/// let expected: &[u8] = &[1, 5, 0, 250, 255, 49, 49, 49, 49, 49];
175172
/// assert_eq!(data.as_ref(), expected);
176173
/// ```
177-
pub fn compress_data(data: &[u8]) -> Result<DataBuf<u8>, Error> {
174+
pub fn compress_data(data: &[u8]) -> Result<DataBuf<u8>, CompressionError> {
178175
let mut out_length: i32 = 0;
179176
// CompressData doesn't actually modify the data, but the header is wrong
180177
let buffer = {
181178
unsafe { ffi::CompressData(data.as_ptr() as *mut _, data.len() as i32, &mut out_length) }
182179
};
183180
DataBuf::new(buffer, out_length)
184-
.ok_or_else(|| error!("could not compress data"))
181+
.ok_or_else(|| CompressionError::CompressionFailed)
185182
}
186183

187184
/// Decompress data (DEFLATE algorythm)
@@ -192,7 +189,7 @@ pub fn compress_data(data: &[u8]) -> Result<DataBuf<u8>, Error> {
192189
/// let data = decompress_data(input).unwrap();
193190
/// assert_eq!(data.as_ref(), expected);
194191
/// ```
195-
pub fn decompress_data(data: &[u8]) -> Result<DataBuf<u8>, Error> {
192+
pub fn decompress_data(data: &[u8]) -> Result<DataBuf<u8>, CompressionError> {
196193
#[cfg(debug_assertions)]
197194
println!("{:?}", data.len());
198195

@@ -202,7 +199,7 @@ pub fn decompress_data(data: &[u8]) -> Result<DataBuf<u8>, Error> {
202199
unsafe { ffi::DecompressData(data.as_ptr() as *mut _, data.len() as i32, &mut out_length) }
203200
};
204201
DataBuf::new(buffer, out_length)
205-
.ok_or_else(|| error!("could not compress data"))
202+
.ok_or_else(|| CompressionError::CompressionFailed)
206203
}
207204

208205
#[cfg(unix)]

0 commit comments

Comments
 (0)