1use std::iter::*;
2
3
4
5#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
6pub enum JniIdentifier<'a> {
7 Namespace(&'a str),
8 ContainingClass(&'a str),
9 LeafClass(&'a str),
10}
11
12
13
14pub struct JniPathIter<'a> {
15 rest: &'a str,
16}
17
18impl<'a> JniPathIter<'a> {
19 pub fn new(path: &'a str) -> Self { JniPathIter { rest: path } }
20}
21
22impl<'a> Iterator for JniPathIter<'a> {
23 type Item = JniIdentifier<'a>;
24 fn next(&mut self) -> Option<Self::Item> {
25 if let Some(slash) = self.rest.find('/') {
26 let (namespace, rest) = self.rest.split_at(slash);
27 self.rest = &rest[1..];
28 return Some(JniIdentifier::Namespace(namespace));
29 }
30
31 if let Some(dollar) = self.rest.find('$') {
32 let (class, rest) = self.rest.split_at(dollar);
33 self.rest = &rest[1..];
34 return Some(JniIdentifier::ContainingClass(class));
35 }
36
37 if !self.rest.is_empty() {
38 let class = self.rest;
39 self.rest = "";
40 return Some(JniIdentifier::LeafClass(class));
41 }
42
43 None
44 }
45}
46
47#[test] fn jni_path_iter() {
48 assert_eq!(JniPathIter::new("").collect::<Vec<JniIdentifier>>(), &[]);
49
50 assert_eq!(JniPathIter::new("Bar").collect::<Vec<JniIdentifier>>(), &[
51 JniIdentifier::LeafClass("Bar"),
52 ]);
53
54 assert_eq!(JniPathIter::new("java/foo/Bar").collect::<Vec<JniIdentifier>>(), &[
55 JniIdentifier::Namespace("java"),
56 JniIdentifier::Namespace("foo"),
57 JniIdentifier::LeafClass("Bar"),
58 ]);
59
60 assert_eq!(JniPathIter::new("java/foo/Bar$Inner").collect::<Vec<JniIdentifier>>(), &[
61 JniIdentifier::Namespace("java"),
62 JniIdentifier::Namespace("foo"),
63 JniIdentifier::ContainingClass("Bar"),
64 JniIdentifier::LeafClass("Inner"),
65 ]);
66
67 assert_eq!(JniPathIter::new("java/foo/Bar$Inner$MoreInner").collect::<Vec<JniIdentifier>>(), &[
68 JniIdentifier::Namespace("java"),
69 JniIdentifier::Namespace("foo"),
70 JniIdentifier::ContainingClass("Bar"),
71 JniIdentifier::ContainingClass("Inner"),
72 JniIdentifier::LeafClass("MoreInner"),
73 ]);
74}
75
76
77
78#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
79pub enum JniField<'a> {
80 Single(JniBasicType<'a>),
81 Array { levels: usize, inner: JniBasicType<'a> },
82}
83
84#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
85pub enum JniBasicType<'a> {
86 Byte,
87 Char,
88 Double,
89 Float,
90 Int,
91 Long,
92 Class(&'a str),
93 Short,
94 Boolean
95}
96
97impl<'a> JniField<'a> {
98 pub fn read_next(remaining: &mut &'a str) -> Result<JniField<'a>, &'static str> {
100 let mut array = 0;
101 let mut chars = remaining.chars();
102
103 let leaf = loop {
104 match chars.next() {
105 None => return Err("Unexpected end of string while parsing for next JNI Field"),
106 Some('B') => { *remaining = chars.as_str(); break JniBasicType::Byte }
107 Some('C') => { *remaining = chars.as_str(); break JniBasicType::Char }
108 Some('D') => { *remaining = chars.as_str(); break JniBasicType::Double }
109 Some('F') => { *remaining = chars.as_str(); break JniBasicType::Float }
110 Some('I') => { *remaining = chars.as_str(); break JniBasicType::Int }
111 Some('J') => { *remaining = chars.as_str(); break JniBasicType::Long }
112 Some('L') => {
113 let chars_str = chars.as_str();
114 if let Some(semi) = chars_str.find(';') {
115 *remaining = &chars_str[(semi+1)..];
116 break JniBasicType::Class(&chars_str[..semi])
117 } else {
118 return Err("Unexpected end of string while parsing for terminating ';' of next JNI Field")
119 }
120 }
121 Some('S') => { *remaining = chars.as_str(); break JniBasicType::Short }
122 Some('Z') => { *remaining = chars.as_str(); break JniBasicType::Boolean }
123 Some('[') => { array += 1; }
124 Some(_ch) => return Err("Unexpected character in JNI type string"),
125 }
126 };
127
128 match array {
129 0 => Ok(JniField::Single(leaf)),
130 n => Ok(JniField::Array { levels: n, inner: leaf }),
131 }
132 }
133
134 pub fn from_str(mut field: &'a str) -> Result<JniField<'a>, &'static str> {
135 let next = Self::read_next(&mut field)?;
136 if field.is_empty() {
137 Ok(next)
138 } else {
139 Err("Expected one type field, got multiple")
140 }
141 }
142}
143
144#[test] fn jni_field_from_str() {
145 assert_eq!(JniField::from_str("F"), Ok(JniField::Single(JniBasicType::Float)));
147 assert_eq!(JniField::from_str("Ljava/foo/Bar;"), Ok(JniField::Single(JniBasicType::Class("java/foo/Bar"))));
148
149 assert_eq!(JniField::from_str("[[F"), Ok(JniField::Array { levels: 2, inner: JniBasicType::Float }));
151 assert_eq!(JniField::from_str("[[[Ljava/foo/Bar;"), Ok(JniField::Array { levels: 3, inner: JniBasicType::Class("java/foo/Bar") }));
152
153 assert!(JniField::from_str("").is_err()); assert!(JniField::from_str("[[").is_err()); assert!(JniField::from_str("Ljava/foo/Bar").is_err()); assert!(JniField::from_str("Ljava/foo/Bar;F").is_err()); assert!(JniField::from_str("Ljava/foo/Bar;Ljava/foo/Bar;").is_err()); let mut class_float = "Ljava/foo/Bar;F";
162 assert_eq!(JniField::read_next(&mut class_float), Ok(JniField::Single(JniBasicType::Class("java/foo/Bar"))));
163 assert_eq!(JniField::read_next(&mut class_float), Ok(JniField::Single(JniBasicType::Float)));
164 assert_eq!(class_float, "");
165 assert!( JniField::read_next(&mut class_float).is_err());
166
167 let mut class_class = "Ljava/foo/Bar;Ljava/foo/Bar;";
168 assert_eq!(JniField::read_next(&mut class_class), Ok(JniField::Single(JniBasicType::Class("java/foo/Bar"))));
169 assert_eq!(JniField::read_next(&mut class_class), Ok(JniField::Single(JniBasicType::Class("java/foo/Bar"))));
170 assert_eq!(class_class, "");
171 assert!( JniField::read_next(&mut class_class).is_err());
172}
173
174
175
176
177
178#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
180pub enum RustIdentifier<'a> {
181 Identifier(&'a str),
183
184 NonIdentifier(&'a str),
187
188 KeywordRawSafe(&'a str),
191
192 KeywordUnderscorePostfix(&'a str),
195}
196
197impl<'a> RustIdentifier<'a> {
198 pub fn from_str(s: &'a str) -> RustIdentifier<'a> {
200 match s {
201 "crate" => RustIdentifier::KeywordUnderscorePostfix("crate_"),
204 "extern" => RustIdentifier::KeywordUnderscorePostfix("extern_"),
205 "self" => RustIdentifier::KeywordUnderscorePostfix("self_"),
206 "super" => RustIdentifier::KeywordUnderscorePostfix("super_"),
207 "Self" => RustIdentifier::KeywordUnderscorePostfix("Self_"),
208
209 "as" => RustIdentifier::KeywordRawSafe("r#as"),
212 "break" => RustIdentifier::KeywordRawSafe("r#break"),
213 "const" => RustIdentifier::KeywordRawSafe("r#const"),
214 "continue" => RustIdentifier::KeywordRawSafe("r#continue"),
215 "else" => RustIdentifier::KeywordRawSafe("r#else"),
216 "enum" => RustIdentifier::KeywordRawSafe("r#enum"),
217 "false" => RustIdentifier::KeywordRawSafe("r#false"),
218 "fn" => RustIdentifier::KeywordRawSafe("r#fn"),
219 "for" => RustIdentifier::KeywordRawSafe("r#for"),
220 "if" => RustIdentifier::KeywordRawSafe("r#if"),
221 "impl" => RustIdentifier::KeywordRawSafe("r#impl"),
222 "in" => RustIdentifier::KeywordRawSafe("r#in"),
223 "let" => RustIdentifier::KeywordRawSafe("r#let"),
224 "loop" => RustIdentifier::KeywordRawSafe("r#loop"),
225 "match" => RustIdentifier::KeywordRawSafe("r#match"),
226 "mod" => RustIdentifier::KeywordRawSafe("r#mod"),
227 "move" => RustIdentifier::KeywordRawSafe("r#move"),
228 "mut" => RustIdentifier::KeywordRawSafe("r#mut"),
229 "pub" => RustIdentifier::KeywordRawSafe("r#pub"),
230 "ref" => RustIdentifier::KeywordRawSafe("r#ref"),
231 "return" => RustIdentifier::KeywordRawSafe("r#return"),
232 "static" => RustIdentifier::KeywordRawSafe("r#static"),
233 "struct" => RustIdentifier::KeywordRawSafe("r#struct"),
234 "trait" => RustIdentifier::KeywordRawSafe("r#trait"),
235 "true" => RustIdentifier::KeywordRawSafe("r#true"),
236 "type" => RustIdentifier::KeywordRawSafe("r#type"),
237 "unsafe" => RustIdentifier::KeywordRawSafe("r#unsafe"),
238 "use" => RustIdentifier::KeywordRawSafe("r#use"),
239 "where" => RustIdentifier::KeywordRawSafe("r#where"),
240 "while" => RustIdentifier::KeywordRawSafe("r#while"),
241 "dyn" => RustIdentifier::KeywordRawSafe("r#dyn"),
242
243 "abstract" => RustIdentifier::KeywordRawSafe("r#abstract"),
246 "become" => RustIdentifier::KeywordRawSafe("r#become"),
247 "box" => RustIdentifier::KeywordRawSafe("r#box"),
248 "do" => RustIdentifier::KeywordRawSafe("r#do"),
249 "final" => RustIdentifier::KeywordRawSafe("r#final"),
250 "macro" => RustIdentifier::KeywordRawSafe("r#macro"),
251 "override" => RustIdentifier::KeywordRawSafe("r#override"),
252 "priv" => RustIdentifier::KeywordRawSafe("r#priv"),
253 "typeof" => RustIdentifier::KeywordRawSafe("r#typeof"),
254 "unsized" => RustIdentifier::KeywordRawSafe("r#unsized"),
255 "virtual" => RustIdentifier::KeywordRawSafe("r#virtual"),
256 "yield" => RustIdentifier::KeywordRawSafe("r#yield"),
257
258 "" => RustIdentifier::NonIdentifier(s),
260 "_" => RustIdentifier::NonIdentifier(s),
261 s if is_rust_identifier(s) => RustIdentifier::Identifier(s),
262 s => RustIdentifier::NonIdentifier(s)
263 }
264 }
265}
266
267#[test] fn rust_identifier_from_str() {
268 assert_eq!(RustIdentifier::from_str("foo") , RustIdentifier::Identifier ("foo") );
269 assert_eq!(RustIdentifier::from_str("crate"), RustIdentifier::KeywordUnderscorePostfix("crate_") );
270 assert_eq!(RustIdentifier::from_str("match"), RustIdentifier::KeywordRawSafe ("r#match"));
271 assert_eq!(RustIdentifier::from_str("föo"), RustIdentifier::NonIdentifier ("föo") );
272 assert_eq!(RustIdentifier::from_str(""), RustIdentifier::NonIdentifier ("") );
273 assert_eq!(RustIdentifier::from_str("_"), RustIdentifier::NonIdentifier ("_") );
274 assert_eq!(RustIdentifier::from_str("_f"), RustIdentifier::Identifier ("_f") );
275 assert_eq!(RustIdentifier::from_str("_1"), RustIdentifier::Identifier ("_1") );
276 assert_eq!(RustIdentifier::from_str("1_"), RustIdentifier::NonIdentifier ("1_") );
277}
278
279fn is_rust_identifier(s: &str) -> bool {
280 let mut chars = s.chars();
282
283 let first_char = if let Some(ch) = chars.next() { ch } else { return false };
285 match first_char {
286 'a'..='z' => {},
287 'A'..='Z' => {},
288 '_' => { if s == "_" { return false } },
289 _ => { return false }
290 }
291
292 while let Some(ch) = chars.next() {
294 match ch {
295 'a'..='z' => {},
296 'A'..='Z' => {},
297 '0'..='9' => {},
298 '_' => {},
299 _ => { return false }
300 }
301 }
302
303 true
304}