1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum MemberValue {
12 Bool(bool),
14 Text(&'static str),
16}
17
18pub type Member = (&'static str, MemberValue);
20
21use MemberValue::{Bool, Text};
22
23pub const ELEMENT_SEARCH: &[Member] = &[
26 ("BEFORE", Text("getElementBefore")),
27 ("AFTER", Text("getElementAfter")),
28 ("AT_OR_BEFORE", Text("getElementAtOrBefore")),
29 ("AT_OR_AFTER", Text("getElementAtOrAfter")),
30 ("BEFORE_OFFSET", Text("getElementBeforeOffset")),
31 ("AFTER_OFFSET", Text("getElementAfterOffset")),
32 ("AT_OR_BEFORE_OFFSET", Text("getElementAtOrBeforeOffset")),
33 ("AT_OR_AFTER_OFFSET", Text("getElementAtOrAfterOffset")),
34 ("BEFORE_NOT_SELF", Text("getElementBeforeNotSelf")),
35 ("AFTER_NOT_SELF", Text("getElementAfterNotSelf")),
36 ("ALL", Text("all")),
37];
38
39pub const OFFSET_SPECIAL: &[Member] = &[
41 ("AT_END", Text("highestTime")),
42 ("LOWEST_OFFSET", Text("lowestOffset")),
43 ("HIGHEST_OFFSET", Text("highestOffset")),
44];
45
46pub const GATHER_SPANNERS: &[Member] = &[
48 ("ALL", Bool(true)),
49 ("NONE", Bool(false)),
50 ("COMPLETE_ONLY", Text("completeOnly")),
51];
52
53pub const APPEND_SPANNERS: &[Member] = &[
56 ("NORMAL", Text("normal")),
57 ("RELATED_ONLY", Text("related_only")),
58 ("NONE", Text("none")),
59];
60
61pub const ORNAMENT_DELAY: &[Member] = &[
63 ("NO_DELAY", Text("noDelay")),
64 ("DEFAULT_DELAY", Text("defaultDelay")),
65];
66
67pub const METER_DIVISION: &[Member] = &[
69 ("FAST", Text("fast")),
70 ("SLOW", Text("slow")),
71 ("NONE", Text("none")),
72];
73
74pub fn hex_numbers(text: &str) -> String {
87 let mut out = String::with_capacity(text.len());
88 let mut digits = String::new();
89 for character in text.chars() {
90 if character.is_ascii_digit() {
91 digits.push(character);
92 continue;
93 }
94 if !digits.is_empty() {
95 out.push_str("0x");
96 out.push_str(&decimal_to_hex(&digits));
97 digits.clear();
98 }
99 out.push(character);
100 }
101 if !digits.is_empty() {
102 out.push_str("0x");
103 out.push_str(&decimal_to_hex(&digits));
104 }
105 out
106}
107
108fn decimal_to_hex(digits: &str) -> String {
110 let mut number: Vec<u8> = digits.bytes().map(|digit| digit - b'0').collect();
111 let mut hex = Vec::new();
112 while number.iter().any(|&digit| digit != 0) {
113 let mut remainder = 0u32;
114 for digit in &mut number {
115 let value = remainder * 10 + u32::from(*digit);
116 *digit = u8::try_from(value / 16).unwrap_or(0);
117 remainder = value % 16;
118 }
119 hex.push(
120 char::from_digit(remainder, 16)
121 .unwrap_or('0')
122 .to_ascii_uppercase(),
123 );
124 }
125 if hex.is_empty() {
126 return "0".to_string();
127 }
128 hex.iter().rev().collect()
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[test]
138 fn every_digit_run_is_written_in_hex() {
139 assert_eq!(hex_numbers("<A2.B: 0>"), "<A0x2.B: 0x0>");
140 assert_eq!(hex_numbers("255"), "0xFF");
141 assert_eq!(hex_numbers("007"), "0x7");
142 assert_eq!(
143 hex_numbers("340282366920938463463374607431768211456"),
144 "0x100000000000000000000000000000000"
145 );
146 assert_eq!(hex_numbers("no digits ß"), "no digits ß");
147 }
148
149 #[test]
151 fn member_names_are_unique() {
152 for table in [
153 ELEMENT_SEARCH,
154 OFFSET_SPECIAL,
155 GATHER_SPANNERS,
156 APPEND_SPANNERS,
157 ORNAMENT_DELAY,
158 METER_DIVISION,
159 ] {
160 let mut names: Vec<_> = table.iter().map(|(name, _)| name).collect();
161 names.sort();
162 names.dedup();
163 assert_eq!(names.len(), table.len());
164 }
165 }
166}