Skip to content

Commit

Permalink
Switch from Box<std::error::Error> to a custom enum, adapted from @fs…
Browse files Browse the repository at this point in the history
…chutt's branch (c.f. issue #55).
  • Loading branch information
aweinstock314 committed Feb 13, 2019
1 parent 07d080b commit 5dc57b0
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 32 deletions.
13 changes: 4 additions & 9 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,16 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

use std::error::Error;

pub fn err(s: &str) -> Box<Error> {
Box::<Error + Send + Sync>::from(s)
}
use error::ClipboardError;

/// Trait for clipboard access
pub trait ClipboardProvider: Sized {
/// Create a context with which to access the clipboard
// TODO: consider replacing Box<Error> with an associated type?
fn new() -> Result<Self, Box<Error>>;
fn new() -> Result<Self, ClipboardError>;
/// Method to get the clipboard contents as a String
fn get_contents(&mut self) -> Result<String, Box<Error>>;
fn get_contents(&mut self) -> Result<String, ClipboardError>;
/// Method to set the clipboard contents as a String
fn set_contents(&mut self, String) -> Result<(), Box<Error>>;
fn set_contents(&mut self, String) -> Result<(), ClipboardError>;
// TODO: come up with some platform-agnostic API for richer types
// than just strings (c.f. issue #31)
}
125 changes: 125 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
use std::fmt::{self, Display, Formatter};

#[cfg(target_os="linux")]
use x11_clipboard_crate::error::Error as X11Error;

use std::string::FromUtf8Error;
use std::error::Error;
use std::io::Error as IoError;

#[derive(Debug)]
pub enum ClipboardError {
Unimplemented,
IoError(IoError),
EncodingError(FromUtf8Error),
#[cfg(target_os = "linux")]
X11ClipboardError(X11Error),
#[cfg(target_os = "macos")]
MacOsClipboardError(MacOsError),
#[cfg(target_os = "windows")]
WindowsClipboardError(WinError),
}

#[cfg(target_os="windows")]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum WinError {
EmptyClipboard,
FormatNoSize,
}

#[cfg(target_os = "windows")]
impl Display for WinError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}", self.description())
}
}

#[cfg(target_os = "windows")]
impl Error for WinError {
fn description(&self) -> &str {
use self::WinError::*;
match *self {
EmptyClipboard => "Empty clipboard or couldn't determine format of clipboard contents",
FormatNoSize => "Could not determine the length of the clipboard contents"
}
}

fn cause(&self) -> Option<&Error> {
None
}
}

impl From<IoError> for ClipboardError {
fn from(e: IoError) -> Self {
ClipboardError::IoError(e)
}
}

#[cfg(target_os="windows")]
impl From<WinError> for ClipboardError {
fn from(e: WinError) -> Self {
ClipboardError::WindowsClipboardError(e)
}
}

#[cfg(target_os="linux")]
impl From<X11Error> for ClipboardError {
fn from(e: X11Error) -> Self {
ClipboardError::X11ClipboardError(e)
}
}

#[cfg(target_os="macos")]
impl From<MacOsError> for ClipboardError {
fn from(e: MacOsError) -> Self {
ClipboardError::MacOsClipboardError(e)
}
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[cfg(target_os = "macos")]
pub enum MacOsError {
PasteWriteObjectsError,
ReadObjectsForClassesEmpty,
ReadObjectsForClassesNull,
PasteboardNotFound,
GeneralPasteboardNotFound,
}

#[cfg(target_os = "macos")]
impl Display for MacOsError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use self::MacOsError::*;
let msg = match *self {
PasteWriteObjectsError => "Could not paste objects to clipboard",
ReadObjectsForClassesEmpty => "Clipboard is empty",
ReadObjectsForClassesNull => "No objects to read",
PasteboardNotFound => "NSPasteboard class not found",
GeneralPasteboardNotFound => "NSPasteboard#generalPasteboard not found",
};
write!(f, "{}", msg)
}
}

impl Display for ClipboardError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use self::ClipboardError::*;
match self {
Unimplemented => write!(f, "Clipboard::Unimplemented: Attempted to get or set the clipboard, which hasn't been implemented yet."),
IoError(ref e) => write!(f, "Clipboard::IoError: {} cause: {:?}", e.description(), e.cause()),
EncodingError(ref e) => write!(f, "Clipboard::EncodingError: {} cause: {:?}", e.description(), e.cause()),
#[cfg(target_os="linux")]
X11ClipboardError(ref e) => write!(f, "X11ClipboardError: {}", e),
#[cfg(target_os="macos")]
MacOsClipboardError(ref e) => write!(f, "MacOsClipboardError: {}", e),
#[cfg(target_os="windows")]
WindowsClipboardError(ref e) => write!(f, "WindowsClipboardError: {} cause: {:?}", e.description(), e.cause()),
}
}
}

impl From<FromUtf8Error> for ClipboardError {
fn from(e: FromUtf8Error) -> Self {
ClipboardError::EncodingError(e)
}
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ extern crate objc_foundation;
mod common;
pub use common::ClipboardProvider;

pub mod error;

#[cfg(all(unix, not(any(target_os="macos", target_os="android", target_os="emscripten"))))]
pub mod x11_clipboard;

Expand Down
12 changes: 6 additions & 6 deletions src/nop_clipboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,22 @@ limitations under the License.
*/

use common::ClipboardProvider;
use std::error::Error;
use error::ClipboardError;

pub struct NopClipboardContext;

impl ClipboardProvider for NopClipboardContext {
fn new() -> Result<NopClipboardContext, Box<Error>> {
fn new() -> Result<NopClipboardContext, ClipboardError> {
Ok(NopClipboardContext)
}
fn get_contents(&mut self) -> Result<String, Box<Error>> {
fn get_contents(&mut self) -> Result<String, ClipboardError> {
println!("Attempting to get the contents of the clipboard, which hasn't yet been \
implemented on this platform.");
Ok("".to_string())
Err(ClipboardError::Unimplemented)
}
fn set_contents(&mut self, _: String) -> Result<(), Box<Error>> {
fn set_contents(&mut self, _: String) -> Result<(), ClipboardError> {
println!("Attempting to set the contents of the clipboard, which hasn't yet been \
implemented on this platform.");
Ok(())
Err(ClipboardError::Unimplemented)
}
}
18 changes: 9 additions & 9 deletions src/osx_clipboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use objc::runtime::{Object, Class};
use objc_foundation::{INSArray, INSString, INSObject};
use objc_foundation::{NSArray, NSDictionary, NSString, NSObject};
use objc_id::{Id, Owned};
use std::error::Error;
use error::{MacOsError, ClipboardError};
use std::mem::transmute;

pub struct OSXClipboardContext {
Expand All @@ -31,16 +31,16 @@ pub struct OSXClipboardContext {
extern "C" {}

impl ClipboardProvider for OSXClipboardContext {
fn new() -> Result<OSXClipboardContext, Box<Error>> {
let cls = try!(Class::get("NSPasteboard").ok_or(err("Class::get(\"NSPasteboard\")")));
fn new() -> Result<OSXClipboardContext, ClipboardError> {
let cls = Class::get("NSPasteboard").ok_or(MacOsError::PasteboardNotFound)?;
let pasteboard: *mut Object = unsafe { msg_send![cls, generalPasteboard] };
if pasteboard.is_null() {
return Err(err("NSPasteboard#generalPasteboard returned null"));
return Err(MacOsError::GeneralPasteboardNotFound.into());
}
let pasteboard: Id<Object> = unsafe { Id::from_ptr(pasteboard) };
Ok(OSXClipboardContext { pasteboard: pasteboard })
}
fn get_contents(&mut self) -> Result<String, Box<Error>> {
fn get_contents(&mut self) -> Result<String, ClipboardError> {
let string_class: Id<NSObject> = {
let cls: Id<Class> = unsafe { Id::from_ptr(class("NSString")) };
unsafe { transmute(cls) }
Expand All @@ -51,24 +51,24 @@ impl ClipboardProvider for OSXClipboardContext {
let obj: *mut NSArray<NSString> =
msg_send![self.pasteboard, readObjectsForClasses:&*classes options:&*options];
if obj.is_null() {
return Err(err("pasteboard#readObjectsForClasses:options: returned null"));
return Err(MacOsError::ReadObjectsForClassesNull.into());
}
Id::from_ptr(obj)
};
if string_array.count() == 0 {
Err(err("pasteboard#readObjectsForClasses:options: returned empty"))
Err(MacOsError::ReadObjectsForClassesEmpty.into())
} else {
Ok(string_array[0].as_str().to_owned())
}
}
fn set_contents(&mut self, data: String) -> Result<(), Box<Error>> {
fn set_contents(&mut self, data: String) -> Result<(), ClipboardError> {
let string_array = NSArray::from_vec(vec![NSString::from_str(&data)]);
let _: usize = unsafe { msg_send![self.pasteboard, clearContents] };
let success: bool = unsafe { msg_send![self.pasteboard, writeObjects:string_array] };
return if success {
Ok(())
} else {
Err(err("NSPasteboard#writeObjects: returned false"))
Err(MacOsError::PasteWriteObjectsError.into())
};
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/windows_clipboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@ limitations under the License.
use clipboard_win::{get_clipboard_string, set_clipboard_string};

use common::ClipboardProvider;
use std::error::Error;
use error::ClipboardError;

pub struct WindowsClipboardContext;

impl ClipboardProvider for WindowsClipboardContext {
fn new() -> Result<Self, Box<Error>> {
fn new() -> Result<Self, ClipboardError> {
Ok(WindowsClipboardContext)
}
fn get_contents(&mut self) -> Result<String, Box<Error>> {
fn get_contents(&mut self) -> Result<String, ClipboardError> {
Ok(get_clipboard_string()?)
}
fn set_contents(&mut self, data: String) -> Result<(), Box<Error>> {
fn set_contents(&mut self, data: String) -> Result<(), ClipboardError> {
Ok(set_clipboard_string(&data)?)
}
}
8 changes: 4 additions & 4 deletions src/x11_clipboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

use std::error::Error;
use error::ClipboardError;
use std::time::Duration;
use std::marker::PhantomData;
use common::*;
Expand Down Expand Up @@ -50,11 +50,11 @@ impl<S> ClipboardProvider for X11ClipboardContext<S>
where
S: Selection,
{
fn new() -> Result<X11ClipboardContext<S>, Box<Error>> {
fn new() -> Result<X11ClipboardContext<S>, ClipboardError> {
Ok(X11ClipboardContext(X11Clipboard::new()?, PhantomData))
}

fn get_contents(&mut self) -> Result<String, Box<Error>> {
fn get_contents(&mut self) -> Result<String, ClipboardError> {
Ok(String::from_utf8(self.0.load(
S::atom(&self.0.getter.atoms),
self.0.getter.atoms.utf8_string,
Expand All @@ -63,7 +63,7 @@ where
)?)?)
}

fn set_contents(&mut self, data: String) -> Result<(), Box<Error>> {
fn set_contents(&mut self, data: String) -> Result<(), ClipboardError> {
Ok(self.0.store(
S::atom(&self.0.setter.atoms),
self.0.setter.atoms.utf8_string,
Expand Down

0 comments on commit 5dc57b0

Please sign in to comment.