1use core::{
2 convert::Infallible,
3 fmt::{Debug, Display},
4};
5
6use alloc::{boxed::Box, vec::Vec};
7use smallvec::SmallVec;
8
9use crate::{
10 Cursor, Parse, ReprForm, TypeParameter, TypeSignature, method::MethodDescriptor,
11 strip_digits_prefix,
12};
13
14#[derive(Debug, Clone, PartialEq, Eq, Hash)]
18pub enum ClassName<'a> {
19 TopLevel(CanonicalClassName<'a>),
21 #[doc(alias = "Generic")]
24 Member {
25 parent: Box<Self>,
27 simple: &'a str,
29 },
30 Local {
32 parent: Box<Self>,
34 simple: &'a str,
36 index: u32,
38 },
39 Anonymous {
41 parent: Box<Self>,
43 index: u32,
45 },
46 #[doc(alias = "ConstructorGeneric")]
49 MethodGeneric {
50 class: Box<Self>,
52 method: MethodDescriptor<'a>,
54 simple: &'a str,
56 },
57}
58
59impl Display for ClassName<'_> {
60 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
61 match self {
62 ClassName::TopLevel(canonical_class_name) => write!(f, "{canonical_class_name}"),
63 ClassName::Member { parent, simple } => write!(f, "{parent}${simple}"),
64 ClassName::Local {
65 parent,
66 simple,
67 index,
68 } => write!(f, "{parent}${index}{simple}"),
69 ClassName::Anonymous { parent, index } => write!(f, "{parent}${index}"),
70 ClassName::MethodGeneric {
71 class,
72 method,
73 simple,
74 } => write!(f, "{class}${method}${simple}"),
75 }
76 }
77}
78
79impl<'a> Parse<'a> for ClassName<'a> {
80 type Error = Infallible;
81
82 fn parse_from(cursor: &mut Cursor<'a>) -> Result<Self, Self::Error> {
83 let s = cursor.get();
84 if let Some((parent, simple)) = s.rsplit_once('$') {
85 if let Some((parent, method)) = parent.rsplit_once('$')
86 && method.chars().next().is_some_and(|c| c == '(')
87 && let Ok(method) = MethodDescriptor::parse_from(&mut Cursor::new(method))
88 {
89 return Ok(Self::MethodGeneric {
90 class: Box::new(Self::parse_from(&mut Cursor::new(parent)).unwrap()),
91 method,
92 simple,
93 });
94 }
95
96 let parent = Box::new(Self::parse_from(&mut Cursor::new(parent))?);
97 let (digits, simple) = strip_digits_prefix(simple);
98 cursor.clear();
99 Ok(match (digits, simple.is_empty()) {
100 (None, _) => Self::Member { parent, simple },
102 (Some(index), true) => Self::Anonymous { parent, index },
103 (Some(index), false) => Self::Local {
104 parent,
105 simple,
106 index,
107 },
108 })
109 } else {
110 CanonicalClassName::parse_from(cursor).map(Self::TopLevel)
111 }
112 }
113}
114
115#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
119pub struct CanonicalClassName<'a> {
120 pub package: Option<&'a str>,
122 pub simple: &'a str,
124 pub form: ReprForm,
126}
127
128impl Display for CanonicalClassName<'_> {
129 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
130 if let Some(pkg) = self.package {
131 write!(f, "{pkg}{}{}", self.form.package_separator(), self.simple)
132 } else {
133 write!(f, "{}", self.simple)
134 }
135 }
136}
137
138impl<'a> Parse<'a> for CanonicalClassName<'a> {
139 type Error = Infallible;
140
141 fn parse_from(cursor: &mut Cursor<'a>) -> Result<Self, Self::Error> {
142 Ok(cursor.advance(|s| {
143 let form = if s.contains('/') {
144 ReprForm::Internal
145 } else {
146 ReprForm::JLS
147 };
148 let (package, c) = s.rsplit_once(form.package_separator()).unzip();
149 (
150 Self {
151 package,
152 simple: c.unwrap_or(s),
153 form,
154 },
155 "",
156 )
157 }))
158 }
159}
160
161#[derive(PartialEq, Eq, Clone)]
163pub struct ClassSignature<'a> {
164 pub params: SmallVec<[TypeParameter<'a>; 1]>,
166 pub extends: TypeSignature<'a>,
168 pub impls: Box<[TypeSignature<'a>]>,
170}
171
172#[derive(Debug, Clone)]
174#[non_exhaustive]
175pub enum InvalidClassSignature {
176 UnclosedAngles,
178 UnknownTypeTag(crate::UnknownTypeTag),
180 ExpectedReference,
182 ExpectedClass,
184}
185
186impl<'a> Parse<'a> for ClassSignature<'a> {
187 type Error = InvalidClassSignature;
188
189 fn parse_from(cursor: &mut Cursor<'a>) -> Result<Self, Self::Error> {
190 let mut params = SmallVec::new();
191 if cursor.0.starts_with('<') {
192 cursor.get_char();
193 let contents = cursor.try_advance(|s| {
194 crate::angle_safe_split(s, &['>']).ok_or(InvalidClassSignature::UnclosedAngles)
195 })?;
196 cursor.get_char();
197 let mut contents = Cursor(contents);
198 crate::parse_type_params(&mut contents, |param| params.push(param))?;
199 }
200
201 Ok(Self {
202 params,
203 extends: {
204 let sig = TypeSignature::parse_from(cursor)?;
205 if !matches!(sig, TypeSignature::Class { .. }) {
206 return Err(InvalidClassSignature::ExpectedClass);
207 }
208 sig
209 },
210 impls: {
211 let mut buf = Vec::new();
212 while !cursor.0.is_empty() {
213 let sig = TypeSignature::parse_from(cursor)?;
214 if !matches!(sig, TypeSignature::Class { .. }) {
215 return Err(InvalidClassSignature::ExpectedClass);
216 }
217 buf.push(sig);
218 }
219 buf.into()
220 },
221 })
222 }
223}
224
225impl Display for ClassSignature<'_> {
226 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
227 if !self.params.is_empty() {
228 crate::display_type_params(&self.params, f)?;
229 }
230 write!(f, "{}", self.extends)?;
231 for sig in &self.impls {
232 write!(f, "{}", sig)?;
233 }
234 Ok(())
235 }
236}
237
238impl Display for InvalidClassSignature {
239 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
240 match self {
241 Self::UnclosedAngles => write!(f, "unclosed angles"),
242 Self::UnknownTypeTag(err) => write!(f, "{err}"),
243 Self::ExpectedReference => {
244 write!(f, "expected type signature to be `ReferenceTypeSignature`")
245 }
246 Self::ExpectedClass => write!(f, "expected type signature to be `ClassTypeSignature`"),
247 }
248 }
249}
250
251impl core::error::Error for InvalidClassSignature {
252 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
253 match self {
254 Self::UnknownTypeTag(err) => Some(err),
255 _ => None,
256 }
257 }
258}
259
260impl From<crate::UnknownTypeTag> for InvalidClassSignature {
261 fn from(value: crate::UnknownTypeTag) -> Self {
262 Self::UnknownTypeTag(value)
263 }
264}
265
266impl From<crate::ParseTypeParamsError> for InvalidClassSignature {
267 fn from(value: crate::ParseTypeParamsError) -> Self {
268 match value {
269 crate::ParseTypeParamsError::UnknownTypeTag(err) => Self::UnknownTypeTag(err),
270 crate::ParseTypeParamsError::ExpectedReference => Self::ExpectedReference,
271 }
272 }
273}
274
275impl Debug for ClassSignature<'_> {
276 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
277 if !self.params.is_empty() {
278 let mut iter = self.params.iter().peekable();
279 write!(f, "<")?;
280 while let Some(param) = iter.next() {
281 write!(f, "{param:?}")?;
282 if iter.peek().is_some() {
283 write!(f, ", ")?;
284 }
285 }
286 write!(f, ">")?;
287 }
288 write!(f, " extends {:?}", self.extends)?;
289 if !self.impls.is_empty() {
290 let mut iter = self.impls.iter().peekable();
291 write!(f, " implements ")?;
292 while let Some(mom) = iter.next() {
293 write!(f, "{mom:?}")?;
294 if iter.peek().is_some() {
295 write!(f, ", ")?;
296 }
297 }
298 }
299 Ok(())
300 }
301}
302
303#[cfg(test)]
304mod tests {
305 use alloc::boxed::Box;
306 use smallvec::SmallVec;
307
308 use crate::{
309 CanonicalClassName, ClassName, ClassSignature, ReducedClassTypeSignature, ReprForm,
310 TypeParameter, TypeSignature, parse, validate_rw,
311 };
312
313 #[test]
314 fn top_level() {
315 assert_eq!(
316 parse::<'_, ClassName<'_>>("java.lang.String").unwrap(),
317 ClassName::TopLevel(CanonicalClassName {
318 package: Some("java.lang"),
319 simple: "String",
320 form: ReprForm::JLS,
321 })
322 );
323
324 assert_eq!(
325 parse::<'_, ClassName<'_>>("Foo").unwrap(),
326 ClassName::TopLevel(CanonicalClassName {
327 package: None,
328 simple: "Foo",
329 form: ReprForm::JLS,
330 })
331 );
332
333 validate_rw::<'_, ClassName<'_>>("java.lang.String");
334 }
335
336 #[test]
337 fn top_level_jvm() {
338 assert_eq!(
339 parse::<'_, ClassName<'_>>("java/lang/String").unwrap(),
340 ClassName::TopLevel(CanonicalClassName {
341 package: Some("java/lang"),
342 simple: "String",
343 form: ReprForm::Internal
344 })
345 );
346
347 validate_rw::<'_, ClassName<'_>>("java/lang/String");
348 }
349
350 #[test]
351 fn member() {
352 assert_eq!(
353 parse::<'_, ClassName<'_>>("java.util.Map$Entry").unwrap(),
354 ClassName::Member {
355 parent: Box::new(ClassName::TopLevel(CanonicalClassName {
356 package: Some("java.util"),
357 simple: "Map",
358 form: ReprForm::JLS
359 })),
360 simple: "Entry"
361 }
362 );
363
364 validate_rw::<'_, ClassName<'_>>("java.util.Map$Entry");
365 }
366
367 #[test]
368 fn local() {
369 assert_eq!(
370 parse::<'_, ClassName<'_>>("com.example.OuterClass$1LocalClass").unwrap(),
371 ClassName::Local {
372 parent: Box::new(ClassName::TopLevel(CanonicalClassName {
373 package: Some("com.example"),
374 simple: "OuterClass",
375 form: ReprForm::JLS
376 })),
377 index: 1,
378 simple: "LocalClass"
379 }
380 );
381
382 validate_rw::<'_, ClassName<'_>>("com.example.OuterClass$1LocalClass");
383 }
384
385 #[test]
386 fn anonymous() {
387 assert_eq!(
388 parse::<'_, ClassName<'_>>("com.example.OuterClass$1").unwrap(),
389 ClassName::Anonymous {
390 parent: Box::new(ClassName::TopLevel(CanonicalClassName {
391 package: Some("com.example"),
392 simple: "OuterClass",
393 form: ReprForm::JLS
394 })),
395 index: 1,
396 }
397 );
398
399 validate_rw::<'_, ClassName<'_>>("com.example.OuterClass$1");
400 }
401
402 #[test]
403 fn class_sig() {
404 assert_eq!(
405 parse::<'_, ClassSignature<'_>>(
406 "Ljava/lang/Object;Ljava/io/Serializable;Ljava/lang/Cloneable;"
407 )
408 .unwrap(),
409 ClassSignature {
410 params: SmallVec::new(),
411 extends: TypeSignature::Class {
412 sig: ReducedClassTypeSignature {
413 name: "java/lang/Object",
414 args: SmallVec::new()
415 },
416 suffix: None
417 },
418 impls: Box::new([
419 TypeSignature::Class {
420 sig: ReducedClassTypeSignature {
421 name: "java/io/Serializable",
422 args: SmallVec::new()
423 },
424 suffix: None
425 },
426 TypeSignature::Class {
427 sig: ReducedClassTypeSignature {
428 name: "java/lang/Cloneable",
429 args: SmallVec::new()
430 },
431 suffix: None
432 },
433 ])
434 }
435 );
436 validate_rw::<'_, ClassSignature<'_>>(
437 "Ljava/lang/Object;Ljava/io/Serializable;Ljava/lang/Cloneable;",
438 );
439
440 assert_eq!(
441 parse::<'_, ClassSignature<'_>>("<T:Ljava/lang/Object;K:V:>Ljava/lang/Object;")
442 .unwrap(),
443 ClassSignature {
444 params: smallvec::smallvec![
445 TypeParameter {
446 name: "T",
447 bound_class: Some(TypeSignature::Class {
448 sig: ReducedClassTypeSignature {
449 name: "java/lang/Object",
450 args: SmallVec::new()
451 },
452 suffix: None
453 }),
454 bound_interface: Box::new([])
455 },
456 TypeParameter {
457 name: "K",
458 bound_class: None,
459 bound_interface: Box::new([])
460 },
461 TypeParameter {
462 name: "V",
463 bound_class: None,
464 bound_interface: Box::new([])
465 }
466 ],
467 extends: TypeSignature::Class {
468 sig: ReducedClassTypeSignature {
469 name: "java/lang/Object",
470 args: SmallVec::new()
471 },
472 suffix: None
473 },
474 impls: Box::new([])
475 }
476 );
477 validate_rw::<'_, ClassSignature<'_>>("<T:Ljava/lang/Object;K:V:>Ljava/lang/Object;");
478 }
479}