1 /*
2 SPDX-License-Identifier: Apache-2.0 OR MIT
3 
4 Copyright 2020 The arboard contributors
5 
6 The project to which this file belongs is licensed under either of
7 the Apache 2.0 or the MIT license at the licensee's choice. The terms
8 and conditions of the chosen license apply to this file.
9 */
10 
11 use std::borrow::Cow;
12 use thiserror::Error;
13 
14 /// An error that might happen during a clipboard operation.
15 ///
16 /// Note that both the `Display` and the `Debug` trait is implemented for this type in such a way
17 /// that they give a short human-readable description of the error; however the documentation
18 /// gives a more detailed explanation for each error kind.
19 #[derive(Error)]
20 pub enum Error {
21 	/// The clipboard contents were not available in the requested format.
22 	/// This could either be due to the clipboard being empty or the clipboard contents having
23 	/// an incompatible format to the requested one (eg when calling `get_image` on text)
24 	#[error("The clipboard contents were not available in the requested format or the clipboard is empty.")]
25 	ContentNotAvailable,
26 
27 	/// The native clipboard is not accessible due to being held by an other party.
28 	///
29 	/// This "other party" could be a different process or it could be within
30 	/// the same program. So for example you may get this error when trying
31 	/// to interact with the clipboard from multiple threads at once.
32 	///
33 	/// Note that it's OK to have multiple `Clipboard` instances. The underlying
34 	/// implementation will make sure that the native clipboard is only
35 	/// opened for transferring data and then closed as soon as possible.
36 	#[error("The native clipboard is not accessible due to being held by an other party.")]
37 	ClipboardOccupied,
38 
39 	/// This can happen in either of the following cases.
40 	///
41 	/// - When returned from `set_image`: the image going to the clipboard cannot be converted to the appropriate format.
42 	/// - When returned from `get_image`: the image coming from the clipboard could not be converted into the `ImageData` struct.
43 	/// - When returned from `get_text`: the text coming from the clipboard is not valid utf-8 or cannot be converted to utf-8.
44 	#[error("The image or the text that was about the be transferred to/from the clipboard could not be converted to the appropriate format.")]
45 	ConversionFailure,
46 
47 	/// Any error that doesn't fit the other error types.
48 	///
49 	/// The `description` field is only meant to help the developer and should not be relied on as a
50 	/// means to identify an error case during runtime.
51 	#[error("Unknown error while interacting with the clipboard: {description}")]
52 	Unknown { description: String },
53 }
54 
55 impl std::fmt::Debug for Error {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result56 	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 		use Error::*;
58 		macro_rules! kind_to_str {
59 			($( $e: pat ),*) => {
60 				match self {
61 					$(
62 						$e => stringify!($e),
63 					)*
64 				}
65 			}
66 		}
67 		let name =
68 			kind_to_str!(ContentNotAvailable, ClipboardOccupied, ConversionFailure, Unknown { .. });
69 		f.write_fmt(format_args!("{} - \"{}\"", name, self))
70 	}
71 }
72 
73 /// Stores pixel data of an image.
74 ///
75 /// Each element in `bytes` stores the value of a channel of a single pixel.
76 /// This struct stores four channels (red, green, blue, alpha) so
77 /// a `3*3` image is going to be stored on `3*3*4 = 36` bytes of data.
78 ///
79 /// The pixels are in row-major order meaning that the second pixel
80 /// in `bytes` (starting at the fifth byte) corresponds to the pixel that's
81 /// sitting to the right side of the top-left pixel (x=1, y=0)
82 ///
83 /// Assigning a `2*1` image would for example look like this
84 /// ```
85 /// use arboard::ImageData;
86 /// use std::borrow::Cow;
87 /// let bytes = [
88 ///     // A red pixel
89 ///     255, 0, 0, 255,
90 ///
91 ///     // A green pixel
92 ///     0, 255, 0, 255,
93 /// ];
94 /// let img = ImageData {
95 ///     width: 2,
96 ///     height: 1,
97 ///     bytes: Cow::from(bytes.as_ref())
98 /// };
99 /// ```
100 #[derive(Debug, Clone)]
101 pub struct ImageData<'a> {
102 	pub width: usize,
103 	pub height: usize,
104 	pub bytes: Cow<'a, [u8]>,
105 }
106 
107 impl<'a> ImageData<'a> {
108 	/// Returns a the bytes field in a way that it's guaranteed to be owned.
109 	/// It moves the bytes if they are already owned and clones them if they are borrowed.
into_owned_bytes(self) -> std::borrow::Cow<'static, [u8]>110 	pub fn into_owned_bytes(self) -> std::borrow::Cow<'static, [u8]> {
111 		self.bytes.into_owned().into()
112 	}
113 
114 	/// Returns an image data that is guaranteed to own its bytes.
115 	/// It moves the bytes if they are already owned and clones them if they are borrowed.
to_owned_img(&self) -> ImageData<'static>116 	pub fn to_owned_img(&self) -> ImageData<'static> {
117 		ImageData {
118 			width: self.width,
119 			height: self.height,
120 			bytes: self.bytes.clone().into_owned().into(),
121 		}
122 	}
123 }
124