2020-03-11 14:09:24 +11:00
|
|
|
//! A wrapper for `NSError`, which can be (and is) bubbled up for certain calls in this library. It
|
|
|
|
//! attempts to be thread safe where possible, and extract the "default" usable information out of
|
|
|
|
//! an `NSError`. This might not be what you need, though, so if it's missing something... well,
|
|
|
|
//! it's up for discussion.
|
|
|
|
|
|
|
|
use std::error;
|
|
|
|
use std::fmt;
|
|
|
|
|
2020-03-16 13:53:09 +11:00
|
|
|
use objc::{class, msg_send, sel, sel_impl};
|
2020-03-11 14:09:24 +11:00
|
|
|
|
2020-03-18 10:55:09 +11:00
|
|
|
use crate::foundation::{id, nil, NSInteger, NSString};
|
2020-03-11 14:09:24 +11:00
|
|
|
|
|
|
|
/// A wrapper around pieces of data extracted from `NSError`. This could be improved: right now, it
|
|
|
|
/// allocates `String` instances when theoretically it could be avoided, and we might be erasing
|
|
|
|
/// certain parts of the `NSError` object that are useful.
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct AppKitError {
|
|
|
|
pub code: usize,
|
|
|
|
pub domain: String,
|
|
|
|
pub description: String
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AppKitError {
|
|
|
|
/// Given an `NSError` (i.e, an id reference) we'll pull out the relevant information and
|
|
|
|
/// configure this. We pull out the information as it makes the error thread safe this way,
|
|
|
|
/// which is... easier, in some cases.
|
2020-03-16 17:10:43 +11:00
|
|
|
pub fn new(error: id) -> Self {
|
2020-03-11 14:09:24 +11:00
|
|
|
let (code, domain, description) = unsafe {
|
|
|
|
let code: usize = msg_send![error, code];
|
2020-03-18 10:55:09 +11:00
|
|
|
let domain = NSString::wrap(msg_send![error, domain]);
|
|
|
|
let description = NSString::wrap(msg_send![error, localizedDescription]);
|
2020-03-11 14:09:24 +11:00
|
|
|
|
|
|
|
(code, domain, description)
|
|
|
|
};
|
|
|
|
|
2020-03-16 17:10:43 +11:00
|
|
|
AppKitError {
|
2020-03-11 14:09:24 +11:00
|
|
|
code: code,
|
2020-03-18 10:55:09 +11:00
|
|
|
domain: domain.to_str().to_string(),
|
|
|
|
description: description.to_str().to_string()
|
2020-03-16 17:10:43 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn boxed(error: id) -> Box<Self> {
|
|
|
|
Box::new(AppKitError::new(error))
|
2020-03-11 14:09:24 +11:00
|
|
|
}
|
2020-03-16 13:53:09 +11:00
|
|
|
|
|
|
|
/// Used for cases where we need to return an `NSError` back to the system (e.g, top-level
|
|
|
|
/// error handling). We just create a new `NSError` so the `AppKitError` crate can be mostly
|
|
|
|
/// thread safe.
|
|
|
|
pub fn into_nserror(self) -> id {
|
|
|
|
unsafe {
|
2020-03-18 10:55:09 +11:00
|
|
|
let domain = NSString::new(&self.domain);
|
2020-03-16 13:53:09 +11:00
|
|
|
let code = self.code as NSInteger;
|
|
|
|
msg_send![class!(NSError), errorWithDomain:domain code:code userInfo:nil]
|
|
|
|
}
|
|
|
|
}
|
2020-03-11 14:09:24 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for AppKitError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "{}", self.description)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl error::Error for AppKitError {}
|