1pub const DICT_VERSION: u8 = 3;
2
3pub const LIST_EMPTY: u8 = 0;
5pub const DICTIONARY_0: u8 = 236;
6pub const DICTIONARY_1: u8 = 237;
7pub const DICTIONARY_2: u8 = 238;
8pub const DICTIONARY_3: u8 = 239;
9
10pub const JID_PAIR: u8 = 250;
11pub const HEX_8: u8 = 251;
12pub const BINARY_8: u8 = 252;
13pub const BINARY_20: u8 = 253;
14pub const BINARY_32: u8 = 254;
15pub const NIBBLE_8: u8 = 255;
16pub const INTEROP_JID: u8 = 245;
17pub const FB_JID: u8 = 246;
18pub const AD_JID: u8 = 247;
19pub const LIST_8: u8 = 248;
20pub const LIST_16: u8 = 249;
21
22pub const PACKED_MAX: u8 = 127;
23pub const SINGLE_BYTE_MAX: u16 = 256;
24
25include!(concat!(env!("OUT_DIR"), "/token_maps.rs"));
27
28pub fn index_of_single_token(token: &str) -> Option<u8> {
30 SINGLE_BYTE_MAP.get(token).copied()
31}
32
33pub fn index_of_double_byte_token(token: &str) -> Option<(u8, u8)> {
34 DOUBLE_BYTE_MAP.get(token).copied()
35}
36
37pub fn get_single_token(index: u8) -> Option<&'static str> {
38 SINGLE_BYTE_TOKENS.get(index as usize).copied()
39}
40
41pub fn get_double_token(dict: u8, index: u8) -> Option<&'static str> {
42 DOUBLE_BYTE_TOKENS
43 .get(dict as usize)
44 .and_then(|d| d.get(index as usize))
45 .copied()
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51
52 #[test]
54 fn test_single_byte_token_roundtrip() {
55 for i in 1u8..=235 {
57 if let Some(token) = get_single_token(i) {
58 let index = index_of_single_token(token);
59 assert_eq!(
60 index,
61 Some(i),
62 "Token '{}' at index {} doesn't round-trip",
63 token,
64 i
65 );
66 }
67 }
68 }
69
70 #[test]
72 fn test_double_byte_token_roundtrip() {
73 for dict in 0..4u8 {
75 for idx in 0..255u8 {
76 if let Some(token) = get_double_token(dict, idx) {
77 let lookup = index_of_double_byte_token(token);
78 assert_eq!(
79 lookup,
80 Some((dict, idx)),
81 "Token '{}' at dict {} index {} doesn't round-trip",
82 token,
83 dict,
84 idx
85 );
86 }
87 }
88 }
89 }
90
91 #[test]
93 fn test_unknown_string_returns_none() {
94 assert!(index_of_single_token("xyzzy_not_a_token_12345").is_none());
96 assert!(index_of_double_byte_token("xyzzy_not_a_token_12345").is_none());
97 }
98
99 #[test]
101 fn test_token_boundary_indices() {
102 let token_0 = get_single_token(0);
104 assert_eq!(token_0, Some(""), "Index 0 should be empty string token");
105
106 assert!(get_single_token(LIST_8).is_none()); assert!(get_single_token(LIST_16).is_none()); assert!(get_single_token(JID_PAIR).is_none()); assert!(get_single_token(HEX_8).is_none()); assert!(get_single_token(BINARY_8).is_none()); assert!(get_single_token(BINARY_20).is_none()); assert!(get_single_token(BINARY_32).is_none()); assert!(get_single_token(NIBBLE_8).is_none()); }
117
118 #[test]
120 fn test_almost_matching_strings() {
121 if let Some(token) = get_single_token(1) {
123 let modified = format!("{}_modified", token);
125 assert!(index_of_single_token(&modified).is_none());
127
128 let prefixed = format!("prefix_{}", token);
130 assert!(index_of_single_token(&prefixed).is_none());
131
132 let suffixed = format!("{}!", token);
134 assert!(index_of_single_token(&suffixed).is_none());
135 }
136 }
137
138 #[test]
140 fn test_out_of_bounds_dictionary() {
141 assert!(get_double_token(4, 0).is_none());
143 assert!(get_double_token(5, 100).is_none());
144 assert!(get_double_token(255, 0).is_none());
145 }
146}