-
Notifications
You must be signed in to change notification settings - Fork 474
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
API: Proper error types instead of String #1424
Draft
rniii
wants to merge
5
commits into
Rust-SDL2:master
Choose a base branch
from
rniii:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,39 +1,102 @@ | ||
use std::error::Error; | ||
use std::fmt; | ||
use std::ffi::{CString, NulError}; | ||
use std::{error, fmt, io}; | ||
|
||
/// A given integer was so big that its representation as a C integer would be | ||
/// negative. | ||
#[derive(Debug, Clone, PartialEq)] | ||
pub enum IntegerOrSdlError { | ||
IntegerOverflows(&'static str, u32), | ||
SdlError(String), | ||
#[derive(Debug)] | ||
pub struct SdlError { | ||
msg: String, | ||
} | ||
|
||
impl SdlError { | ||
pub fn from_last_error() -> Self { | ||
let msg = crate::get_error(); | ||
Self { msg } | ||
} | ||
|
||
pub(crate) fn from_string(msg: String) -> Self { | ||
Self { msg } | ||
} | ||
|
||
pub fn message(&self) -> &str { | ||
&self.msg | ||
} | ||
} | ||
|
||
impl fmt::Display for SdlError { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
write!(f, "{}", self.msg) | ||
} | ||
} | ||
|
||
impl error::Error for SdlError {} | ||
|
||
#[derive(Debug)] | ||
pub enum Error { | ||
Sdl(SdlError), | ||
Io(io::Error), | ||
/// An integer was larger than [`i32::MAX`] in a parameter, and it can't be converted to a C int | ||
IntOverflow(&'static str, u32), | ||
/// A null byte was found within a parameter, and it can't be sent to SDL | ||
InvalidString(NulError, &'static str), | ||
} | ||
|
||
impl Error { | ||
pub fn from_sdl_error() -> Self { | ||
Self::Sdl(SdlError::from_last_error()) | ||
} | ||
} | ||
|
||
impl fmt::Display for Error { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
match self { | ||
Self::Sdl(msg) => write!(f, "SDL error: {msg}"), | ||
Self::Io(err) => write!(f, "IO error: {err}"), | ||
Self::IntOverflow(name, value) => write!(f, "Integer '{name}' overflows: {value}"), | ||
Self::InvalidString(name, nul) => write!(f, "Invalid string '{name}': {nul}"), | ||
} | ||
} | ||
} | ||
|
||
impl error::Error for Error { | ||
fn source(&self) -> Option<&(dyn error::Error + 'static)> { | ||
match self { | ||
Self::Sdl(..) | Self::IntOverflow(..) => None, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The source may also be returned for |
||
Self::Io(err) => Some(err), | ||
Self::InvalidString(nul, _) => Some(nul), | ||
} | ||
} | ||
} | ||
|
||
impl From<SdlError> for Error { | ||
fn from(value: SdlError) -> Self { | ||
Self::Sdl(value) | ||
} | ||
} | ||
|
||
impl From<io::Error> for Error { | ||
fn from(value: io::Error) -> Self { | ||
Self::Io(value) | ||
} | ||
} | ||
|
||
pub fn validate_string(str: impl Into<Vec<u8>>, name: &'static str) -> Result<CString, Error> { | ||
match CString::new(str) { | ||
Ok(c) => Ok(c), | ||
Err(nul) => Err(Error::InvalidString(nul, name)), | ||
} | ||
} | ||
|
||
/// Validates and converts the given u32 to a positive C integer. | ||
pub fn validate_int(value: u32, name: &'static str) -> Result<::libc::c_int, IntegerOrSdlError> { | ||
use self::IntegerOrSdlError::*; | ||
pub fn validate_int(value: u32, name: &'static str) -> Result<libc::c_int, Error> { | ||
// Many SDL functions will accept `int` values, even if it doesn't make sense | ||
// for the values to be negative. | ||
// In the cases that SDL doesn't check negativity, passing negative values | ||
// could be unsafe. | ||
// For example, `SDL_JoystickGetButton` uses the index argument to access an | ||
// array without checking if it's negative, which could potentially lead to | ||
// segmentation faults. | ||
if value >= 1 << 31 { | ||
Err(IntegerOverflows(name, value)) | ||
if value > libc::c_int::MAX as u32 { | ||
Err(Error::IntOverflow(name, value)) | ||
} else { | ||
Ok(value as ::libc::c_int) | ||
} | ||
} | ||
|
||
impl fmt::Display for IntegerOrSdlError { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
use self::IntegerOrSdlError::*; | ||
|
||
match *self { | ||
IntegerOverflows(name, value) => write!(f, "Integer '{}' overflows ({})", name, value), | ||
SdlError(ref e) => write!(f, "SDL error: {}", e), | ||
} | ||
Ok(value as libc::c_int) | ||
} | ||
} | ||
|
||
impl Error for IntegerOrSdlError {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the definition the first field is the
NulError
, not the name.To prevent these bugs (in this crate but also user code using this crate) I advise to use a struct like variant instead of a tuple like one. This also adds context to the context-less
&'static str
field. I suggest to change the definition toInvalidString { nul_err: NulError, var_name: &'static str }
(or something like this) and roughly the same forIntOverflow
.