Skip to main content

rs_clip_bridge_types/
lib.rs

1//! Shared types for rs-clip-bridge
2//!
3//! This crate contains common data structures used by both the client and server.
4
5use serde::{
6    Deserialize,
7    Serialize,
8};
9
10/// Clipboard content type
11#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
12pub enum ClipboardContent {
13    Image {
14        bytes: Vec<u8>,
15        height: usize,
16        width: usize,
17    },
18    Text(String),
19    Raw(Vec<u8>),
20}
21
22/// Event data sent when clipboard content changes.
23///
24/// Content is encrypted using ChaCha20-Poly1305.
25#[derive(Clone, Debug, Deserialize, Serialize)]
26pub struct ClipboardEventData {
27    /// Optional device name that originated this event
28    pub device_name: Option<String>,
29
30    /// Encrypted content: `[ciphertext || poly1305_tag]`
31    pub content: Vec<u8>,
32
33    /// ChaCha20-Poly1305 nonce (12 bytes)
34    pub nonce: Vec<u8>,
35
36    /// Unix timestamp in milliseconds
37    pub timestamp: u64,
38}
39
40// ================================================================================================
41// Tests
42// ================================================================================================
43
44#[cfg(test)]
45mod tests {
46    use postcard::{
47        from_bytes,
48        to_allocvec,
49    };
50
51    use super::*;
52
53    #[test]
54    fn clipboard_event_data_serde() {
55        let data = ClipboardEventData {
56            device_name: Some("test-device".to_string()),
57            content: vec![0xde, 0xad, 0xbe, 0xef],
58            nonce: vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c],
59            timestamp: 1234567890,
60        };
61
62        let encoded = to_allocvec(&data).unwrap();
63        let decoded: ClipboardEventData = from_bytes(&encoded).unwrap();
64        assert_eq!(decoded.device_name, data.device_name);
65        assert_eq!(decoded.content, data.content);
66        assert_eq!(decoded.nonce, data.nonce);
67        assert_eq!(decoded.timestamp, data.timestamp);
68    }
69
70    #[test]
71    fn clipboard_content_serde() {
72        let content = ClipboardContent::Text("Hello, World!".to_string());
73        let encoded = to_allocvec(&content).unwrap();
74        let decoded: ClipboardContent = from_bytes(&encoded).unwrap();
75        assert_eq!(decoded, content);
76
77        let raw = ClipboardContent::Raw(vec![0xff, 0x00, 0xff]);
78        let encoded = to_allocvec(&raw).unwrap();
79        let decoded: ClipboardContent = from_bytes(&encoded).unwrap();
80        assert_eq!(decoded, raw);
81
82        let image = ClipboardContent::Image {
83            bytes: vec![0x89, 0x50, 0x4e],
84            height: 1,
85            width: 1,
86        }; // PNG magic
87
88        let encoded = to_allocvec(&image).unwrap();
89        let decoded: ClipboardContent = from_bytes(&encoded).unwrap();
90        assert_eq!(decoded, image);
91    }
92
93    #[test]
94    fn clipboard_event_data_no_device_name() {
95        let data = ClipboardEventData {
96            device_name: None,
97            content: vec![0u8; 32],
98            nonce: vec![0u8; 12],
99            timestamp: 0,
100        };
101
102        let encoded = to_allocvec(&data).unwrap();
103        let decoded: ClipboardEventData = from_bytes(&encoded).unwrap();
104        assert_eq!(decoded.device_name, None);
105    }
106}