ragc_common/
stream_naming.rs

1// Stream naming utilities for AGC archives
2// Matches C++ utils.cpp stream naming conventions
3
4/// Convert integer to custom base64 encoding (matches C++ int_to_base64)
5/// Uses digits: 0-9, A-Z, a-z, _, #
6pub fn int_to_base64(mut n: u32) -> String {
7    const DIGITS: &[u8; 64] = b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_#";
8
9    let mut result = String::new();
10
11    loop {
12        result.push(DIGITS[(n & 0x3f) as usize] as char);
13        n /= 64;
14        if n == 0 {
15            break;
16        }
17    }
18
19    result
20}
21
22/// Get stream prefix based on archive version
23pub fn stream_prefix(archive_version: u32) -> &'static str {
24    if archive_version < 3000 {
25        "seg-"
26    } else {
27        "x"
28    }
29}
30
31/// Get base stream name
32pub fn stream_base(archive_version: u32, n: u32) -> String {
33    if archive_version < 3000 {
34        format!("seg-{n}")
35    } else {
36        format!("x{}", int_to_base64(n))
37    }
38}
39
40/// Get reference stream name
41pub fn stream_ref_name(archive_version: u32, n: u32) -> String {
42    if archive_version < 3000 {
43        format!("seg-{n}-ref")
44    } else {
45        format!("x{}r", int_to_base64(n))
46    }
47}
48
49/// Get delta stream name
50pub fn stream_delta_name(archive_version: u32, n: u32) -> String {
51    if archive_version < 3000 {
52        format!("seg-{n}-delta")
53    } else {
54        format!("x{}d", int_to_base64(n))
55    }
56}
57
58/// Get reference extension
59pub fn stream_ref_ext(archive_version: u32) -> &'static str {
60    if archive_version < 3000 {
61        "-ref"
62    } else {
63        "r"
64    }
65}
66
67/// Get delta extension
68pub fn stream_delta_ext(archive_version: u32) -> &'static str {
69    if archive_version < 3000 {
70        "-delta"
71    } else {
72        "d"
73    }
74}
75
76#[cfg(test)]
77mod tests {
78    use super::*;
79
80    #[test]
81    fn test_int_to_base64() {
82        // Test basic values
83        assert_eq!(int_to_base64(0), "0");
84        assert_eq!(int_to_base64(1), "1");
85        assert_eq!(int_to_base64(9), "9");
86        assert_eq!(int_to_base64(10), "A");
87        assert_eq!(int_to_base64(35), "Z");
88        assert_eq!(int_to_base64(36), "a");
89        assert_eq!(int_to_base64(61), "z");
90        assert_eq!(int_to_base64(62), "_");
91        assert_eq!(int_to_base64(63), "#");
92
93        // Test multi-digit values
94        assert_eq!(int_to_base64(64), "01"); // 64 = 1*64 + 0
95        assert_eq!(int_to_base64(65), "11"); // 65 = 1*64 + 1
96    }
97
98    #[test]
99    fn test_stream_naming_v3() {
100        let version = 3000;
101
102        assert_eq!(stream_prefix(version), "x");
103        assert_eq!(stream_base(version, 0), "x0");
104        assert_eq!(stream_base(version, 1), "x1");
105        assert_eq!(stream_base(version, 10), "xA");
106
107        assert_eq!(stream_ref_name(version, 0), "x0r");
108        assert_eq!(stream_delta_name(version, 0), "x0d");
109
110        assert_eq!(stream_ref_ext(version), "r");
111        assert_eq!(stream_delta_ext(version), "d");
112    }
113
114    #[test]
115    fn test_stream_naming_legacy() {
116        let version = 2000;
117
118        assert_eq!(stream_prefix(version), "seg-");
119        assert_eq!(stream_base(version, 0), "seg-0");
120        assert_eq!(stream_base(version, 1), "seg-1");
121
122        assert_eq!(stream_ref_name(version, 0), "seg-0-ref");
123        assert_eq!(stream_delta_name(version, 0), "seg-0-delta");
124
125        assert_eq!(stream_ref_ext(version), "-ref");
126        assert_eq!(stream_delta_ext(version), "-delta");
127    }
128}