1use crate::Encoding;
4
5const QUALIFIERS: &'static [char] = &[
6 'r', 'n', 'N', 'o', 'O', 'R', 'V', ];
14
15fn rm_enc_prefix<'a>(s: &'a str, enc: &Encoding) -> Option<&'a str> {
16 use Encoding::*;
17 let code = match *enc {
18 Char => "c",
19 Short => "s",
20 Int => "i",
21 Long => "l",
22 LongLong => "q",
23 UChar => "C",
24 UShort => "S",
25 UInt => "I",
26 ULong => "L",
27 ULongLong => "Q",
28 Float => "f",
29 Double => "d",
30 Bool => "B",
31 Void => "v",
32 String => "*",
33 Object => "@",
34 Block => "@?",
35 Class => "#",
36 Sel => ":",
37 Unknown => "?",
38 BitField(b) => {
39 let s = rm_prefix(s, "b")?;
40 return rm_int_prefix(s, b);
41 }
42 Pointer(t) => {
43 let s = rm_prefix(s, "^")?;
44 return rm_enc_prefix(s, t);
45 }
46 Array(len, item) => {
47 let mut s = s;
48 s = rm_prefix(s, "[")?;
49 s = rm_int_prefix(s, len)?;
50 s = rm_enc_prefix(s, item)?;
51 return rm_prefix(s, "]");
52 }
53 Struct(name, fields) => {
54 let mut s = s;
55 s = rm_prefix(s, "{")?;
56 s = rm_prefix(s, name)?;
57 s = rm_prefix(s, "=")?;
58 for field in fields {
59 s = rm_enc_prefix(s, field)?;
60 }
61 return rm_prefix(s, "}");
62 }
63 Union(name, members) => {
64 let mut s = s;
65 s = rm_prefix(s, "(")?;
66 s = rm_prefix(s, name)?;
67 s = rm_prefix(s, "=")?;
68 for member in members {
69 s = rm_enc_prefix(s, member)?;
70 }
71 return rm_prefix(s, ")");
72 }
73 };
74
75 rm_prefix(s, code)
76}
77
78fn chomp_int(s: &str) -> Option<(u32, &str)> {
79 let (num, t) = match s.find(|c: char| !c.is_digit(10)) {
81 Some(i) => s.split_at(i),
82 None => (s, ""),
83 };
84 num.parse().map(|n| (n, t)).ok()
85}
86
87fn rm_int_prefix(s: &str, other: u32) -> Option<&str> {
88 chomp_int(s)
89 .and_then(|(n, t)| if other == n { Some(t) } else { None })
90}
91
92fn rm_prefix<'a>(s: &'a str, other: &str) -> Option<&'a str> {
93 if s.starts_with(other) {
94 Some(&s[other.len()..])
95 } else {
96 None
97 }
98}
99
100pub fn eq_enc(s: &str, enc: &Encoding) -> bool {
101 let s = s.trim_start_matches(QUALIFIERS);
103
104 rm_enc_prefix(s, enc).map_or(false, str::is_empty)
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112
113 #[test]
114 fn test_nested() {
115 let enc = Encoding::Struct("A", &[
116 Encoding::Struct("B", &[
117 Encoding::Char,
118 Encoding::Int,
119 ]),
120 Encoding::Char,
121 Encoding::Int,
122 ]);
123 assert!(eq_enc("{A={B=ci}ci}", &enc));
124 assert!(!eq_enc("{A={B=ci}ci", &enc));
125
126 }
127
128 #[test]
129 fn test_bitfield() {
130 assert!(eq_enc("b32", &Encoding::BitField(32)));
131 assert!(!eq_enc("b", &Encoding::BitField(32)));
132 assert!(!eq_enc("b-32", &Encoding::BitField(32)));
133 }
134
135 #[test]
136 fn test_qualifiers() {
137 assert!(eq_enc("Vv", &Encoding::Void));
138 assert!(eq_enc("r*", &Encoding::String));
139 }
140
141 #[test]
142 fn test_unicode() {
143 let fields = &[Encoding::Char, Encoding::Int];
144 assert!(eq_enc("{☃=ci}", &Encoding::Struct("☃", fields)));
145 }
146}