rsfn-file 0.3.1

Utilitário para arquivos que trafegam na RSFN (Rede do Sistema Financeiro Nacional)
Documentation
use std::{ffi::OsStr, fmt};

/// Indicador de tratamento especial.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SpecialTreatment {
    Normal,
    UsingNotEnabledCert,
    NotCryptBroadcast,
    NotCrypt,
    NotCompress,
    NotCompressAndNotCrypt,
    Compress,
    CompressWithoutCrypt,
    Unknown(u8),
}

impl From<[u8; 1]> for SpecialTreatment {
    fn from(value: [u8; 1]) -> Self {
        value[0].into()
    }
}

impl From<u8> for SpecialTreatment {
    fn from(value: u8) -> Self {
        match value {
            0 => Self::Normal,
            1 => Self::UsingNotEnabledCert,
            2 => Self::NotCryptBroadcast,
            3 => Self::NotCrypt,
            4 => Self::NotCompress,
            6 => Self::NotCompressAndNotCrypt,
            8 => Self::Compress,
            10 => Self::CompressWithoutCrypt,
            n => Self::Unknown(n),
        }
    }
}

impl From<&OsStr> for SpecialTreatment {
    fn from(value: &OsStr) -> Self {
        let value = value.to_string_lossy();
        if let Some(value) = value.strip_prefix("0x") {
            u8::from_str_radix(value, 16)
        } else if let Some(value) = value.strip_prefix("0b") {
            u8::from_str_radix(value, 2)
        } else if let Some(value) = value.strip_prefix("0") {
            u8::from_str_radix(value, 8)
        } else {
            value.parse()
        }
        .unwrap_or(0xff)
        .into()
    }
}

impl SpecialTreatment {
    pub fn value(&self) -> u8 {
        match self {
            Self::Normal => 0,
            Self::UsingNotEnabledCert => 1,
            Self::NotCryptBroadcast => 2,
            Self::NotCrypt => 3,
            Self::NotCompress => 4,
            Self::NotCompressAndNotCrypt => 6,
            Self::Compress => 8,
            Self::CompressWithoutCrypt => 10,
            Self::Unknown(n) => *n,
        }
    }

    pub fn describe_value(&self) -> String {
        match self {
            Self::Normal => "Uso normal".to_string(),
            Self::UsingNotEnabledCert => {
                "Utiliza um certificado digital ainda não ativado".to_string()
            }
            Self::NotCryptBroadcast => "Não cifrada para o destinatário (broadcast)".to_string(),
            Self::NotCrypt => "Não cifrada que pode ser relativa à segurança".to_string(),
            Self::NotCompress => "Arquivo não compactado".to_string(),
            Self::NotCompressAndNotCrypt => "Arquivo não compactado e sem cifragem".to_string(),
            Self::Compress => "Arquivo compactado".to_string(),
            Self::CompressWithoutCrypt => "Arquivo compactado sem cifragem".to_string(),
            Self::Unknown(_) => "DESCONHECIDO".to_string(),
        }
    }

    pub fn is_valid(&self) -> bool {
        !matches!(self, Self::Unknown(_))
    }

    pub fn to_bytes(&self) -> [u8; 1] {
        [self.value()]
    }
}

impl fmt::Display for SpecialTreatment {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let value = self.value();
        let desc = self.describe_value();
        write!(f, "0x{value:02x} [{desc}]")
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn value_normal() {
        let sut: SpecialTreatment = [0].into();

        assert_eq!(sut, SpecialTreatment::Normal);
        assert_eq!(sut, 0.into());
        assert_eq!(sut.value(), 0);
        assert_eq!(sut.describe_value(), "Uso normal");
        assert!(sut.is_valid());
        assert_eq!(sut.to_bytes(), [0]);
        assert_eq!(sut.to_string(), "0x00 [Uso normal]");
    }

    #[test]
    fn value_using_not_enabled_cert() {
        let sut: SpecialTreatment = [1].into();

        assert_eq!(sut, SpecialTreatment::UsingNotEnabledCert);
        assert_eq!(sut, 1.into());
        assert_eq!(sut.value(), 1);
        assert_eq!(
            sut.describe_value(),
            "Utiliza um certificado digital ainda não ativado"
        );
        assert!(sut.is_valid());
        assert_eq!(sut.to_bytes(), [1]);
        assert_eq!(
            sut.to_string(),
            "0x01 [Utiliza um certificado digital ainda não ativado]"
        );
    }

    #[test]
    fn value_not_crypt_broadcast() {
        let sut: SpecialTreatment = [2].into();

        assert_eq!(sut, SpecialTreatment::NotCryptBroadcast);
        assert_eq!(sut, 2.into());
        assert_eq!(sut.value(), 2);
        assert_eq!(
            sut.describe_value(),
            "Não cifrada para o destinatário (broadcast)"
        );
        assert!(sut.is_valid());
        assert_eq!(sut.to_bytes(), [2]);
        assert_eq!(
            sut.to_string(),
            "0x02 [Não cifrada para o destinatário (broadcast)]"
        );
    }

    #[test]
    fn value_not_crypt() {
        let sut: SpecialTreatment = [3].into();

        assert_eq!(sut, SpecialTreatment::NotCrypt);
        assert_eq!(sut, 3.into());
        assert_eq!(sut.value(), 3);
        assert_eq!(
            sut.describe_value(),
            "Não cifrada que pode ser relativa à segurança"
        );
        assert!(sut.is_valid());
        assert_eq!(sut.to_bytes(), [3]);
        assert_eq!(
            sut.to_string(),
            "0x03 [Não cifrada que pode ser relativa à segurança]"
        );
    }

    #[test]
    fn value_not_compress() {
        let sut: SpecialTreatment = [4].into();

        assert_eq!(sut, SpecialTreatment::NotCompress);
        assert_eq!(sut, 4.into());
        assert_eq!(sut.value(), 4);
        assert_eq!(sut.describe_value(), "Arquivo não compactado");
        assert!(sut.is_valid());
        assert_eq!(sut.to_bytes(), [4]);
        assert_eq!(sut.to_string(), "0x04 [Arquivo não compactado]");
    }

    #[test]
    fn value_not_compress_and_not_crypt() {
        let sut: SpecialTreatment = [6].into();

        assert_eq!(sut, SpecialTreatment::NotCompressAndNotCrypt);
        assert_eq!(sut, 6.into());
        assert_eq!(sut.value(), 6);
        assert_eq!(
            sut.describe_value(),
            "Arquivo não compactado e sem cifragem"
        );
        assert!(sut.is_valid());
        assert_eq!(sut.to_bytes(), [6]);
        assert_eq!(
            sut.to_string(),
            "0x06 [Arquivo não compactado e sem cifragem]"
        );
    }

    #[test]
    fn value_compress() {
        let sut: SpecialTreatment = [8].into();

        assert_eq!(sut, SpecialTreatment::Compress);
        assert_eq!(sut, 8.into());
        assert_eq!(sut.value(), 8);
        assert_eq!(sut.describe_value(), "Arquivo compactado");
        assert!(sut.is_valid());
        assert_eq!(sut.to_bytes(), [8]);
        assert_eq!(sut.to_string(), "0x08 [Arquivo compactado]");
    }

    #[test]
    fn value_compress_without_crypt() {
        let sut: SpecialTreatment = [10].into();

        assert_eq!(sut, SpecialTreatment::CompressWithoutCrypt);
        assert_eq!(sut, 10.into());
        assert_eq!(sut.value(), 10);
        assert_eq!(sut.describe_value(), "Arquivo compactado sem cifragem");
        assert!(sut.is_valid());
        assert_eq!(sut.to_bytes(), [10]);
        assert_eq!(sut.to_string(), "0x0a [Arquivo compactado sem cifragem]");
    }

    #[test]
    fn value_unknown() {
        let sut: SpecialTreatment = [11].into();

        assert_eq!(sut, SpecialTreatment::Unknown(11));
        assert_eq!(sut, 11.into());
        assert_eq!(sut.value(), 11);
        assert_eq!(sut.describe_value(), "DESCONHECIDO");
        assert!(!sut.is_valid());
        assert_eq!(sut.to_bytes(), [11]);
        assert_eq!(sut.to_string(), "0x0b [DESCONHECIDO]");
    }
}