summaryrefslogtreecommitdiffstats
path: root/third_party/rust/alsa/src/error.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/alsa/src/error.rs')
-rw-r--r--third_party/rust/alsa/src/error.rs100
1 files changed, 100 insertions, 0 deletions
diff --git a/third_party/rust/alsa/src/error.rs b/third_party/rust/alsa/src/error.rs
new file mode 100644
index 0000000000..02debb8a52
--- /dev/null
+++ b/third_party/rust/alsa/src/error.rs
@@ -0,0 +1,100 @@
+#![macro_use]
+
+use libc::{c_void, c_int, c_char, free};
+use std::{fmt, str};
+use std::ffi::CStr;
+use std::error::Error as StdError;
+
+/// ALSA error
+///
+/// Most ALSA functions can return a negative error code.
+/// If so, then that error code is wrapped into this `Error` struct.
+/// An Error is also returned in case ALSA returns a string that
+/// cannot be translated into Rust's UTF-8 strings.
+#[derive(Debug, Clone, PartialEq, Copy)]
+pub struct Error(&'static str, nix::Error);
+
+pub type Result<T> = ::std::result::Result<T, Error>;
+
+macro_rules! acheck {
+ ($f: ident ( $($x: expr),* ) ) => {{
+ let r = unsafe { alsa::$f( $($x),* ) };
+ if r < 0 { Err(Error::new(stringify!($f), -r as ::libc::c_int)) }
+ else { Ok(r) }
+ }}
+}
+
+pub fn from_const<'a>(func: &'static str, s: *const c_char) -> Result<&'a str> {
+ if s.is_null() { return Err(invalid_str(func)) };
+ let cc = unsafe { CStr::from_ptr(s) };
+ str::from_utf8(cc.to_bytes()).map_err(|_| invalid_str(func))
+}
+
+pub fn from_alloc(func: &'static str, s: *mut c_char) -> Result<String> {
+ if s.is_null() { return Err(invalid_str(func)) };
+ let c = unsafe { CStr::from_ptr(s) };
+ let ss = str::from_utf8(c.to_bytes()).map_err(|_| {
+ unsafe { free(s as *mut c_void); }
+ invalid_str(func)
+ })?.to_string();
+ unsafe { free(s as *mut c_void); }
+ Ok(ss)
+}
+
+pub fn from_code(func: &'static str, r: c_int) -> Result<c_int> {
+ if r < 0 { Err(Error::new(func, r)) }
+ else { Ok(r) }
+}
+
+impl Error {
+ pub fn new(func: &'static str, res: c_int) -> Error {
+ let errno = nix::errno::Errno::from_i32(res as i32);
+ Error(func, errno)
+ }
+
+ pub fn unsupported(func: &'static str) -> Error {
+ Error(func, nix::Error::ENOTSUP)
+ }
+
+ /// The function which failed.
+ pub fn func(&self) -> &'static str { self.0 }
+
+
+ /// Underlying error
+ ///
+ /// Match this against the re-export of `nix::Error` in this crate, not against a specific version
+ /// of the nix crate. The nix crate version might be updated with minor updates of this library.
+ pub fn errno(&self) -> nix::Error { self.1 }
+
+ /// Underlying error
+ ///
+ /// Match this against the re-export of `nix::Error` in this crate, not against a specific version
+ /// of the nix crate. The nix crate version might be updated with minor updates of this library.
+ pub fn nix_error(&self) -> nix::Error { self.1 }
+}
+
+pub fn invalid_str(func: &'static str) -> Error { Error(func, nix::Error::EILSEQ) }
+
+impl StdError for Error {
+ fn source(&self) -> Option<&(dyn StdError + 'static)> { Some(&self.1) }
+ fn description(&self) -> &str { "ALSA error" }
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "ALSA function '{}' failed with error '{}'", self.0, self.1)
+ }
+}
+
+impl From<Error> for fmt::Error {
+ fn from(_: Error) -> fmt::Error { fmt::Error }
+}
+
+
+#[test]
+fn broken_pcm_name() {
+ use std::ffi::CString;
+ let e = crate::PCM::open(&*CString::new("this_PCM_does_not_exist").unwrap(), crate::Direction::Playback, false).err().unwrap();
+ assert_eq!(e.func(), "snd_pcm_open");
+ assert_eq!(e.errno(), nix::errno::Errno::ENOENT);
+}