ragc_common/
types.rs

1// AGC Core Types and Constants
2// Rust equivalent of src/common/defs.h
3
4/// Version information
5pub const AGC_VER_MAJOR: u32 = 3;
6pub const AGC_VER_MINOR: u32 = 2;
7pub const AGC_VER_BUGFIX: u32 = 1;
8pub const AGC_VER_BUILD: &str = "20241125.1";
9
10/// Archive file format version
11pub const AGC_FILE_MAJOR: u32 = 3;
12pub const AGC_FILE_MINOR: u32 = 0;
13
14/// Contig separator byte in packed-contig mode (0xFF)
15/// C++ uses this to pack multiple contigs into a single compressed part
16pub const CONTIG_SEPARATOR: u8 = 0xFF;
17
18/// Full version string
19pub fn agc_version() -> String {
20    format!(
21        "AGC (Assembled Genomes Compressor) v. {AGC_VER_MAJOR}.{AGC_VER_MINOR}.{AGC_VER_BUGFIX} [build {AGC_VER_BUILD}]"
22    )
23}
24
25/// A contig (genome sequence) represented as a vector of bytes
26/// Each byte typically represents a nucleotide base
27pub type Contig = Vec<u8>;
28
29/// A packed/compressed data block
30pub type PackedBlock = Vec<u8>;
31
32/// Nucleotide encoding (A=0, C=1, G=2, T=3)
33#[repr(u8)]
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub enum Base {
36    A = 0,
37    C = 1,
38    G = 2,
39    T = 3,
40}
41
42impl Base {
43    /// Convert a character to a base (A/C/G/T -> 0/1/2/3)
44    #[inline]
45    pub fn from_char(c: char) -> Option<Self> {
46        match c.to_ascii_uppercase() {
47            'A' => Some(Base::A),
48            'C' => Some(Base::C),
49            'G' => Some(Base::G),
50            'T' => Some(Base::T),
51            _ => None,
52        }
53    }
54
55    /// Convert a base to a character (0/1/2/3 -> A/C/G/T)
56    #[inline]
57    pub fn to_char(self) -> char {
58        match self {
59            Base::A => 'A',
60            Base::C => 'C',
61            Base::G => 'G',
62            Base::T => 'T',
63        }
64    }
65
66    /// Get the complement base
67    #[inline]
68    pub fn complement(self) -> Self {
69        match self {
70            Base::A => Base::T,
71            Base::C => Base::G,
72            Base::G => Base::C,
73            Base::T => Base::A,
74        }
75    }
76
77    /// Convert u8 value to Base
78    #[inline]
79    pub fn from_u8(val: u8) -> Option<Self> {
80        match val {
81            0 => Some(Base::A),
82            1 => Some(Base::C),
83            2 => Some(Base::G),
84            3 => Some(Base::T),
85            _ => None,
86        }
87    }
88}
89
90#[cfg(test)]
91mod tests {
92    use super::*;
93
94    #[test]
95    fn test_base_encoding() {
96        assert_eq!(Base::from_char('A'), Some(Base::A));
97        assert_eq!(Base::from_char('C'), Some(Base::C));
98        assert_eq!(Base::from_char('G'), Some(Base::G));
99        assert_eq!(Base::from_char('T'), Some(Base::T));
100        assert_eq!(Base::from_char('N'), None);
101    }
102
103    #[test]
104    fn test_base_complement() {
105        assert_eq!(Base::A.complement(), Base::T);
106        assert_eq!(Base::T.complement(), Base::A);
107        assert_eq!(Base::C.complement(), Base::G);
108        assert_eq!(Base::G.complement(), Base::C);
109    }
110
111    #[test]
112    fn test_version_string() {
113        let version = agc_version();
114        assert!(version.contains("3.2.1"));
115        assert!(version.contains("20241125.1"));
116    }
117}