flow_fcs/
datatype.rs

1use anyhow::{Result, anyhow};
2use serde::{Deserialize, Serialize};
3use strum_macros::Display;
4
5/// The data type of the FCS file, which determines how event data is stored
6///
7/// FCS files can store data in different numeric formats. The most common is
8/// single-precision floating point (F), which is also the default.
9#[derive(Default, Display, Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash)]
10pub enum FcsDataType {
11    /// Unsigned binary integer
12    I,
13    /// Single-precision floating point (f32)
14    #[default]
15    F,
16    /// Double-precision floating point (f64)
17    D,
18    /// ASCII-encoded string (not supported)
19    A,
20}
21impl FcsDataType {
22    /// Matches the string pattern and returns the corresponding data type
23    /// # Errors
24    /// Will return `Err` if `data_type` is not a valid data type (ASCII-encoded strings are not supported, but binary integers, single-precision floating point, and double-precision floating point are supported)
25    pub fn from_keyword_str(data_type: &str) -> Result<Self> {
26        match data_type {
27            "I" => Ok(Self::I),
28            "F" => Ok(Self::F),
29            "D" => Ok(Self::D),
30            "A" => Err(anyhow!("ASCII-encoded string data type not supported")),
31            _ => Err(anyhow!("Invalid data type")),
32        }
33    }
34
35    /// Returns the keyword string representation of the data type
36    pub fn to_keyword_str(&self) -> &str {
37        match self {
38            Self::I => "I (unsigned binary integer)",
39            Self::F => "F (single-precision floating point)",
40            Self::D => "D (double-precision floating point)",
41            Self::A => "A (ASCII-encoded string)",
42        }
43    }
44
45    /// Returns the number of bytes for the data type based on the number of bits
46    ///
47    /// This is used in conjunction with `$PnB` to determine the actual bytes per parameter.
48    /// For `I` (integer) type, the actual bytes depend on `$PnB` (e.g., 16 bits = 2 bytes, 32 bits = 4 bytes).
49    /// For `F` (float32), always 4 bytes.
50    /// For `D` (float64), always 8 bytes.
51    ///
52    /// # Arguments
53    /// * `bits` - Number of bits from `$PnB` keyword
54    ///
55    /// # Returns
56    /// Number of bytes for this data type with the given bit width
57    #[must_use]
58    pub fn get_bytes_for_bits(&self, bits: usize) -> usize {
59        match self {
60            Self::I => (bits + 7) / 8, // Convert bits to bytes, rounding up
61            Self::F => 4,
62            Self::D => 8,
63            Self::A => 0,
64        }
65    }
66}