hdc_rs/
file.rs

1//! File transfer types and options for HDC
2
3/// File transfer options for send/recv operations
4#[derive(Debug, Clone, Default)]
5pub struct FileTransferOptions {
6    /// Hold target file timestamp (-a)
7    hold_timestamp: bool,
8    /// Sync mode: only update newer files (-sync)
9    sync_mode: bool,
10    /// Compress transfer (-z)
11    /// Note: May not improve efficiency for already compressed files
12    compress: bool,
13    /// Mode sync (-m)
14    mode_sync: bool,
15    /// Send/receive file to debug application directory (-b)
16    debug_dir: bool,
17}
18
19impl FileTransferOptions {
20    /// Create new file transfer options with defaults
21    pub fn new() -> Self {
22        Self::default()
23    }
24
25    /// Hold target file timestamp
26    pub fn hold_timestamp(mut self, enable: bool) -> Self {
27        self.hold_timestamp = enable;
28        self
29    }
30
31    /// Enable sync mode (only update newer files)
32    pub fn sync_mode(mut self, enable: bool) -> Self {
33        self.sync_mode = enable;
34        self
35    }
36
37    /// Enable compression during transfer
38    pub fn compress(mut self, enable: bool) -> Self {
39        self.compress = enable;
40        self
41    }
42
43    /// Enable mode sync
44    pub fn mode_sync(mut self, enable: bool) -> Self {
45        self.mode_sync = enable;
46        self
47    }
48
49    /// Send/receive to debug application directory
50    pub fn debug_dir(mut self, enable: bool) -> Self {
51        self.debug_dir = enable;
52        self
53    }
54
55    /// Convert options to command flags string
56    pub(crate) fn to_flags(&self) -> String {
57        let mut flags = Vec::new();
58
59        if self.hold_timestamp {
60            flags.push("-a");
61        }
62        if self.sync_mode {
63            flags.push("-sync");
64        }
65        if self.compress {
66            flags.push("-z");
67        }
68        if self.mode_sync {
69            flags.push("-m");
70        }
71        if self.debug_dir {
72            flags.push("-b");
73        }
74
75        flags.join(" ")
76    }
77}
78
79/// File transfer direction
80#[derive(Debug, Clone, Copy, PartialEq, Eq)]
81pub enum FileTransferDirection {
82    /// Send file from local to remote device
83    Send,
84    /// Receive file from remote device to local
85    Recv,
86}
87
88/// Validate file path for transfer
89pub(crate) fn validate_path(path: &str) -> bool {
90    !path.is_empty() && !path.contains('\0')
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96
97    #[test]
98    fn test_file_options_flags() {
99        let opts = FileTransferOptions::new()
100            .hold_timestamp(true)
101            .compress(true);
102        assert_eq!(opts.to_flags(), "-a -z");
103
104        let opts = FileTransferOptions::new().sync_mode(true).mode_sync(true);
105        assert_eq!(opts.to_flags(), "-sync -m");
106    }
107
108    #[test]
109    fn test_validate_path() {
110        assert!(validate_path("/data/local/tmp/test.txt"));
111        assert!(validate_path("test.txt"));
112        assert!(!validate_path(""));
113        assert!(!validate_path("test\0file"));
114    }
115}