• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Name substitutions for JNI name mangling. See
16 //! <https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#resolving_native_method_names>
17 //! for spec details.
18 
substitute_method_chars(s: &str) -> String19 pub fn substitute_method_chars(s: &str) -> String {
20     s.chars()
21         .flat_map(|c| -> CharIter {
22             match c {
23                 '$' => "_00024".into(),
24                 '_' => "_1".into(),
25                 _ => c.into(),
26             }
27         })
28         .collect()
29 }
30 
substitute_package_chars(s: &str) -> String31 pub fn substitute_package_chars(s: &str) -> String {
32     s.chars()
33         .flat_map(|c| -> CharIter {
34             match c {
35                 '.' => "_".into(),
36                 '$' => "_00024".into(),
37                 '_' => "_1".into(),
38                 _ => c.into(),
39             }
40         })
41         .collect()
42 }
43 
substitute_class_chars(s: &str) -> String44 pub fn substitute_class_chars(s: &str) -> String {
45     s.chars()
46         .flat_map(|c| -> CharIter {
47             match c {
48                 // Use dot or dollar for inner classes: `'.' -> '$' -> "_00024"`
49                 '.' | '$' => "_00024".into(),
50                 '_' => "_1".into(),
51                 _ => c.into(),
52             }
53         })
54         .collect()
55 }
56 
57 /// A `char` iterator that can be created from either a `char` or a `&'static str`.
58 enum CharIter {
59     One(core::option::IntoIter<char>),
60     Many(core::str::Chars<'static>),
61 }
62 
63 impl Iterator for CharIter {
64     type Item = char;
next(&mut self) -> Option<char>65     fn next(&mut self) -> Option<char> {
66         match *self {
67             Self::One(ref mut iter) => iter.next(),
68             Self::Many(ref mut iter) => iter.next(),
69         }
70     }
71 }
72 
73 impl From<char> for CharIter {
from(c: char) -> Self74     fn from(c: char) -> Self {
75         Self::One(Some(c).into_iter())
76     }
77 }
78 
79 impl From<&'static str> for CharIter {
from(s: &'static str) -> Self80     fn from(s: &'static str) -> Self {
81         Self::Many(s.chars())
82     }
83 }
84 
85 #[cfg(test)]
86 mod tests {
87     use super::*;
88 
89     #[test]
test_char_iter_one()90     fn test_char_iter_one() {
91         let seq = CharIter::from('a').collect::<String>();
92         assert_eq!("a", &seq);
93     }
94 
95     #[test]
test_char_iter_many()96     fn test_char_iter_many() {
97         let seq = CharIter::from("asdf").collect::<String>();
98         assert_eq!("asdf", &seq);
99     }
100 
101     #[test]
test_substitute_method_chars()102     fn test_substitute_method_chars() {
103         let mangled = substitute_method_chars("method_with_under$cores");
104         assert_eq!("method_1with_1under_00024cores", &mangled);
105     }
106 
107     #[test]
test_substitute_package_chars()108     fn test_substitute_package_chars() {
109         let mangled = substitute_package_chars("com.weird_name.java");
110         assert_eq!("com_weird_1name_java", &mangled);
111     }
112 
113     #[test]
test_substitute_class_chars()114     fn test_substitute_class_chars() {
115         // Both dot and dollar should work here
116 
117         let mangled = substitute_class_chars("Foo.Inner");
118         assert_eq!("Foo_00024Inner", &mangled);
119 
120         let mangled = substitute_class_chars("Foo$Inner");
121         assert_eq!("Foo_00024Inner", &mangled);
122     }
123 }
124