Skip to main content

java_bin_name/
class.rs

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/// Binary name of a class or interface.
15///
16/// See [JLS 13.1](https://docs.oracle.com/javase/specs/jls/se25/html/jls-13.html#jls-13.1).
17#[derive(Debug, Clone, PartialEq, Eq, Hash)]
18pub enum ClassName<'a> {
19    /// Binary name of a top level class or interface.
20    TopLevel(CanonicalClassName<'a>),
21    /// Binary name of a member class or interface, or
22    /// a type variable declared by a generic class or interface.
23    #[doc(alias = "Generic")]
24    Member {
25        /// The binary name of its immediately enclosing class or interface.
26        parent: Box<Self>,
27        /// The simple name of the member or the type variable.
28        simple: &'a str,
29    },
30    /// Binary name of a local class or interface.
31    Local {
32        /// The binary name of its immediately enclosing class or interface.
33        parent: Box<Self>,
34        /// The simple name of the local class.
35        simple: &'a str,
36        /// A non-empty sequence of digits.
37        index: u32,
38    },
39    /// Binary name of an anonymous class.
40    Anonymous {
41        /// The binary name of its immediately enclosing class or interface.
42        parent: Box<Self>,
43        /// A non-empty sequence of digits.
44        index: u32,
45    },
46    /// Binary name of a type variable declared by a generic method, or
47    /// a constructor.
48    #[doc(alias = "ConstructorGeneric")]
49    MethodGeneric {
50        /// The binary name of the class or interface declaring the method or constructor.
51        class: Box<Self>,
52        /// The descriptor of the method or constructor.
53        method: MethodDescriptor<'a>,
54        /// The simple name of the type variable.
55        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                // expected non-empty, but have to handle errors that way
101                (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/// Canonical, or fully qualified name of a class or interface.
116///
117/// See [JLS 6.7](https://docs.oracle.com/javase/specs/jls/se25/html/jls-6.html#jls-6.7).
118#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
119pub struct CanonicalClassName<'a> {
120    /// The fully qualified name of the package.
121    pub package: Option<&'a str>,
122    /// The simple name of the class or interface.
123    pub simple: &'a str,
124    /// The representation form of this class name.
125    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/// Signature of a class or interface declaration.
162#[derive(PartialEq, Eq, Clone)]
163pub struct ClassSignature<'a> {
164    /// Generic parameters.
165    pub params: SmallVec<[TypeParameter<'a>; 1]>,
166    /// Super class.
167    pub extends: TypeSignature<'a>,
168    /// Super interfaces.
169    pub impls: Box<[TypeSignature<'a>]>,
170}
171
172/// Errors encountered while parsing a class signature.
173#[derive(Debug, Clone)]
174#[non_exhaustive]
175pub enum InvalidClassSignature {
176    /// Unclosed angles.
177    UnclosedAngles,
178    /// Unknown type signature tag.
179    UnknownTypeTag(crate::UnknownTypeTag),
180    /// Expected `ReferenceTypeSignature`.
181    ExpectedReference,
182    /// Expected `ClassTypeSignature`.
183    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}