quick_file_transfer/config/transfer/
command.rs

1use serde::{Deserialize, Serialize};
2use strum_macros::{Display, EnumIter};
3
4use crate::config::compression::CompressionVariant;
5
6#[derive(Debug, Default, Serialize, Deserialize, EnumIter, PartialEq, Display)]
7pub enum DestinationMode {
8    /// Transfering a single file to a path where the parent exists (there's no requirement to the basename)
9    #[default]
10    SingleFile,
11    /// Transferring multiple files, the path must be to an existent directory
12    MultipleFiles,
13    /// Transferring recursively from a directory, the basename must be an existent directory or the parent is (must not be file or invalid parent).
14    RecusiveDirectory,
15}
16
17/// Defines commands a QFT client can issue to a QFT server
18#[derive(Debug, Serialize, Deserialize, EnumIter)]
19#[allow(variant_size_differences)]
20pub enum ServerCommand {
21    GetFreePort((Option<u16>, Option<u16>)),
22    Prealloc(u64, String),
23    ReceiveData(u32, String, Option<CompressionVariant>),
24    EndOfTransfer,
25    IsDestinationValid(DestinationMode, String),
26}
27
28impl ServerCommand {
29    /// The length of the command header that describes how long the command is (in bytes).
30    ///
31    /// # Note
32    /// TODO: Revisit this before 1.0
33    pub const HEADER_SIZE: usize = 1;
34
35    /// Takes an array of bytes describing the header size and returns how size of the incoming command in bytes
36    pub fn size_from_bytes(raw_header: [u8; Self::HEADER_SIZE]) -> usize {
37        u8::from_be_bytes(raw_header) as usize
38    }
39}
40
41#[derive(Debug, Serialize, Deserialize, EnumIter, PartialEq)]
42pub enum ServerResult {
43    Ok,
44    Err(Box<str>),
45}
46
47impl ServerResult {
48    pub const HEADER_SIZE: usize = 2;
49
50    pub fn err<S>(err_msg: S) -> Self
51    where
52        S: Into<Box<str>>,
53    {
54        Self::Err(err_msg.into())
55    }
56
57    /// Takes an array of bytes describing the header size and returns the size of the incoming command in bytes
58    pub fn size_from_bytes(raw_header: [u8; Self::HEADER_SIZE]) -> usize {
59        u16::from_be_bytes(raw_header) as usize
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66    use strum::IntoEnumIterator;
67    use testresult::TestResult;
68
69    /// Assert that each variant is less than 128 bytes
70    #[test]
71    fn test_command_serialized_size_constraint() -> TestResult {
72        let enum_size = std::mem::size_of::<ServerCommand>();
73        eprintln!("Enum size: {enum_size}");
74        assert!(enum_size < 255);
75
76        for cmd_variant in ServerCommand::iter() {
77            let serialized = bincode::serialize(&cmd_variant)?;
78            let serialized_size = serialized.len();
79            eprintln!("Serialized {cmd_variant:?} size={serialized_size}");
80            assert!(serialized_size < 128);
81        }
82
83        Ok(())
84    }
85}