Skip to main content

fission_core/
platform_clipboard.rs

1//! Clipboard host capabilities.
2
3use crate::capability::{CapabilityType, OperationCapability};
4use crate::DataStreamId;
5use serde::{Deserialize, Serialize};
6
7#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
8pub struct ClipboardText {
9    pub text: Option<String>,
10}
11
12#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
13pub struct ClipboardWriteTextRequest {
14    pub text: String,
15}
16
17#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
18pub struct ClipboardItem {
19    /// MIME type for this clipboard item.
20    pub content_type: String,
21    /// Runtime-owned stream containing this item payload.
22    pub stream: DataStreamId,
23    /// Total byte length when the host can determine it up front.
24    pub byte_len: Option<u64>,
25    /// Optional filename or display name associated with this item.
26    pub suggested_name: Option<String>,
27}
28
29#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
30pub struct ClipboardContent {
31    pub items: Vec<ClipboardItem>,
32}
33
34#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
35pub struct ClipboardError {
36    pub code: String,
37    pub message: String,
38}
39
40impl ClipboardError {
41    /// Creates a portable clipboard error payload.
42    ///
43    /// `code` should be a stable, machine-readable reason such as
44    /// `unsupported`, `permission_denied`, or `timeout`. `message` should be a
45    /// concise human-readable explanation suitable for logs or developer-facing
46    /// diagnostics.
47    pub fn new(code: impl Into<String>, message: impl Into<String>) -> Self {
48        Self {
49            code: code.into(),
50            message: message.into(),
51        }
52    }
53
54    /// Creates the standard unsupported-operation error for this capability.
55    ///
56    /// `operation` should name the attempted clipboard operation. Use this
57    /// from hosts that implement the capability contract but cannot provide this
58    /// operation on the current platform or hardware.
59    pub fn unsupported(operation: impl Into<String>) -> Self {
60        Self::new(
61            "unsupported",
62            format!(
63                "clipboard operation `{}` is not supported by this host",
64                operation.into()
65            ),
66        )
67    }
68}
69
70pub struct ReadClipboardTextCapability;
71impl OperationCapability for ReadClipboardTextCapability {
72    type Request = ();
73    type Ok = ClipboardText;
74    type Err = ClipboardError;
75}
76
77pub struct WriteClipboardTextCapability;
78impl OperationCapability for WriteClipboardTextCapability {
79    type Request = ClipboardWriteTextRequest;
80    type Ok = ();
81    type Err = ClipboardError;
82}
83
84pub struct ReadClipboardContentCapability;
85impl OperationCapability for ReadClipboardContentCapability {
86    type Request = ();
87    type Ok = ClipboardContent;
88    type Err = ClipboardError;
89}
90
91pub struct WriteClipboardContentCapability;
92impl OperationCapability for WriteClipboardContentCapability {
93    type Request = ClipboardContent;
94    type Ok = ();
95    type Err = ClipboardError;
96}
97
98pub struct ClearClipboardCapability;
99impl OperationCapability for ClearClipboardCapability {
100    type Request = ();
101    type Ok = ();
102    type Err = ClipboardError;
103}
104
105pub const READ_CLIPBOARD_TEXT: CapabilityType<ReadClipboardTextCapability> =
106    CapabilityType::new("fission.clipboard.read_text");
107pub const WRITE_CLIPBOARD_TEXT: CapabilityType<WriteClipboardTextCapability> =
108    CapabilityType::new("fission.clipboard.write_text");
109pub const READ_CLIPBOARD_CONTENT: CapabilityType<ReadClipboardContentCapability> =
110    CapabilityType::new("fission.clipboard.read_content");
111pub const WRITE_CLIPBOARD_CONTENT: CapabilityType<WriteClipboardContentCapability> =
112    CapabilityType::new("fission.clipboard.write_content");
113pub const CLEAR_CLIPBOARD: CapabilityType<ClearClipboardCapability> =
114    CapabilityType::new("fission.clipboard.clear");
115
116#[cfg(test)]
117mod tests {
118    use super::*;
119
120    #[test]
121    fn clipboard_text_round_trips() {
122        let request = ClipboardWriteTextRequest {
123            text: "copy me".into(),
124        };
125        let bytes = serde_json::to_vec(&request).unwrap();
126        let decoded: ClipboardWriteTextRequest = serde_json::from_slice(&bytes).unwrap();
127        assert_eq!(decoded, request);
128    }
129
130    #[test]
131    fn clipboard_content_round_trips() {
132        let content = ClipboardContent {
133            items: vec![ClipboardItem {
134                content_type: "text/plain".into(),
135                stream: DataStreamId(42),
136                byte_len: Some(7),
137                suggested_name: None,
138            }],
139        };
140        let bytes = serde_json::to_vec(&content).unwrap();
141        let decoded: ClipboardContent = serde_json::from_slice(&bytes).unwrap();
142        assert_eq!(decoded, content);
143    }
144}