1use core::fmt::{Debug, Display, Write as _};
2
3use alloc::boxed::Box;
4use smallvec::SmallVec;
5
6use crate::{Cursor, Parse, angle_safe_split};
7
8#[derive(Debug, Clone)]
10pub struct UnknownTypeTag(char);
11
12impl core::error::Error for UnknownTypeTag {}
13
14impl Display for UnknownTypeTag {
15 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
16 write!(f, "unknown field type '{}'", self.0)
17 }
18}
19
20#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
22#[allow(missing_docs)]
23pub enum PrimitiveType {
24 Byte,
25 Char,
26 Double,
27 Float,
28 Int,
29 Long,
30 Short,
31 Boolean,
32}
33
34impl PrimitiveType {
35 #[inline]
37 pub const fn key(self) -> char {
38 match self {
39 Self::Byte => 'B',
40 Self::Char => 'C',
41 Self::Double => 'D',
42 Self::Float => 'F',
43 Self::Int => 'I',
44 Self::Long => 'J',
45 Self::Short => 'S',
46 Self::Boolean => 'Z',
47 }
48 }
49}
50
51impl Debug for PrimitiveType {
52 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
53 match self {
54 Self::Byte => write!(f, "byte"),
55 Self::Char => write!(f, "char"),
56 Self::Double => write!(f, "double"),
57 Self::Float => write!(f, "float"),
58 Self::Int => write!(f, "int"),
59 Self::Long => write!(f, "long"),
60 Self::Short => write!(f, "short"),
61 Self::Boolean => write!(f, "boolean"),
62 }
63 }
64}
65
66#[derive(Clone, PartialEq, Eq, Hash)]
70#[allow(missing_docs)] pub enum FieldType<'a> {
72 Primitive(PrimitiveType),
73 Class(&'a str),
74 Array(Box<Self>),
75}
76
77impl Display for FieldType<'_> {
78 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
79 match self {
80 Self::Primitive(ty) => f.write_char(ty.key()),
81 Self::Class(class_name) => write!(f, "L{class_name};"),
82 Self::Array(field_ty) => write!(f, "[{field_ty}"),
83 }
84 }
85}
86
87impl<'a> Parse<'a> for FieldType<'a> {
88 type Error = UnknownTypeTag;
89
90 fn parse_from(cursor: &mut Cursor<'a>) -> Result<Self, Self::Error> {
91 let leading = cursor.get_char();
92 match leading {
93 'B' => Ok(Self::Primitive(PrimitiveType::Byte)),
94 'C' => Ok(Self::Primitive(PrimitiveType::Char)),
95 'D' => Ok(Self::Primitive(PrimitiveType::Double)),
96 'F' => Ok(Self::Primitive(PrimitiveType::Float)),
97 'I' => Ok(Self::Primitive(PrimitiveType::Int)),
98 'J' => Ok(Self::Primitive(PrimitiveType::Long)),
99 'S' => Ok(Self::Primitive(PrimitiveType::Short)),
100 'Z' => Ok(Self::Primitive(PrimitiveType::Boolean)),
101 'L' => cursor
102 .try_advance(|s| s.split_once(';').ok_or(UnknownTypeTag('L')))
103 .map(Self::Class),
104 '[' => Self::parse_from(cursor).map(|t| Self::Array(Box::new(t))),
105 _ => Err(UnknownTypeTag(leading)),
106 }
107 }
108}
109
110impl Debug for FieldType<'_> {
111 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
112 match self {
113 Self::Primitive(ty) => Debug::fmt(ty, f),
114 Self::Class(arg0) => Debug::fmt(arg0, f),
115 Self::Array(arg0) => {
116 Debug::fmt(arg0, f)?;
117 write!(f, "[]")
118 }
119 }
120 }
121}
122
123#[derive(Clone, PartialEq, Eq)]
127#[allow(missing_docs, variant_size_differences)]
128pub enum TypeSignature<'a> {
129 Primitive(PrimitiveType),
130 Class {
131 sig: ReducedClassTypeSignature<'a>,
132 suffix: Option<ReducedClassTypeSignature<'a>>,
133 },
134 Type(&'a str),
135 Array(Box<Self>),
136}
137
138#[derive(Clone, PartialEq, Eq)]
142#[doc(alias = "SimpleClassTypeSignature")]
143pub struct ReducedClassTypeSignature<'a> {
144 pub name: &'a str,
146 pub args: SmallVec<[Option<Box<TypeArgument<'a>>>; 1]>,
150}
151
152#[derive(Clone, PartialEq, Eq)]
154pub struct TypeArgument<'a> {
155 pub kind: TypeArgumentKind,
157 pub signature: TypeSignature<'a>,
159}
160
161#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
163#[allow(missing_docs)]
164pub enum TypeArgumentKind {
165 #[default]
166 Exact,
167 Extends,
169 Super,
171}
172
173impl Display for TypeSignature<'_> {
174 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
175 match self {
176 TypeSignature::Primitive(ty) => write!(f, "{}", ty.key()),
177 TypeSignature::Class { sig, suffix } => {
178 write!(f, "L{}", sig)?;
179 if let Some(suffix) = suffix {
180 write!(f, ".{}", suffix)?;
181 }
182 write!(f, ";")?;
183 Ok(())
184 }
185 TypeSignature::Type(ty) => write!(f, "T{};", ty),
186 TypeSignature::Array(ty) => write!(f, "[{}", ty),
187 }
188 }
189}
190
191impl Display for ReducedClassTypeSignature<'_> {
192 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
193 write!(f, "{}", self.name)?;
194 if !self.args.is_empty() {
195 write!(f, "<")?;
196 for arg in &self.args {
197 if let Some(arg) = arg {
198 write!(f, "{}", arg)?;
199 } else {
200 write!(f, "*")?;
201 }
202 }
203 write!(f, ">")?;
204 }
205 Ok(())
206 }
207}
208
209impl Display for TypeArgument<'_> {
210 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
211 match self.kind {
212 TypeArgumentKind::Exact => (),
213 TypeArgumentKind::Extends => write!(f, "+")?,
214 TypeArgumentKind::Super => write!(f, "-")?,
215 }
216 write!(f, "{}", self.signature)?;
217 Ok(())
218 }
219}
220
221impl<'a> Parse<'a> for TypeSignature<'a> {
222 type Error = UnknownTypeTag;
223
224 fn parse_from(cursor: &mut Cursor<'a>) -> Result<Self, Self::Error> {
225 let leading = cursor.get_char();
226 match leading {
227 'B' => Ok(Self::Primitive(PrimitiveType::Byte)),
228 'C' => Ok(Self::Primitive(PrimitiveType::Char)),
229 'D' => Ok(Self::Primitive(PrimitiveType::Double)),
230 'F' => Ok(Self::Primitive(PrimitiveType::Float)),
231 'I' => Ok(Self::Primitive(PrimitiveType::Int)),
232 'J' => Ok(Self::Primitive(PrimitiveType::Long)),
233 'S' => Ok(Self::Primitive(PrimitiveType::Short)),
234 'Z' => Ok(Self::Primitive(PrimitiveType::Boolean)),
235 'L' => {
236 let major = cursor
237 .try_advance(|s| angle_safe_split(s, &[';', '.']).ok_or(UnknownTypeTag('L')))?;
238 let suffix = match cursor.get_char() {
239 '.' => {
240 let suffix = cursor.try_advance(|s| {
241 angle_safe_split(s, &[';']).ok_or(UnknownTypeTag('L'))
242 })?;
243 cursor.get_char();
244 Some(suffix)
245 }
246 ';' => None,
247 _ => unreachable!(),
248 };
249
250 Ok(Self::Class {
251 sig: ReducedClassTypeSignature::parse_from(&mut Cursor(major))?,
252 suffix: suffix
253 .map(|src| ReducedClassTypeSignature::parse_from(&mut Cursor(src)))
254 .transpose()?,
255 })
256 }
257 'T' => cursor
258 .try_advance(|s| s.split_once(';').ok_or(UnknownTypeTag('T')))
259 .map(Self::Type),
260 '[' => Self::parse_from(cursor).map(|t| Self::Array(Box::new(t))),
261 _ => Err(UnknownTypeTag(leading)),
262 }
263 }
264}
265
266impl<'a> Parse<'a> for ReducedClassTypeSignature<'a> {
267 type Error = UnknownTypeTag;
268
269 fn parse_from(input: &mut Cursor<'a>) -> Result<Self, UnknownTypeTag> {
270 let src = input.get();
271 input.0 = "";
272 let (name, rem) = src.split_once('<').unzip();
273 let name = name.unwrap_or(src);
274 let mut args = SmallVec::new();
275 if let Some(rem) = rem {
276 let mut cursor = Cursor(rem.strip_suffix('>').unwrap_or(rem));
277 while !cursor.0.is_empty() {
278 let mut c1 = Cursor(cursor.0);
279 if c1.get_char() == '*' {
280 args.push(None);
281 cursor = c1;
282 } else {
283 args.push(Some(Box::new(TypeArgument::parse_from(&mut cursor)?)));
284 }
285 }
286 }
287 Ok(Self { name, args })
288 }
289}
290
291impl<'a> Parse<'a> for TypeArgument<'a> {
292 type Error = UnknownTypeTag;
293
294 fn parse_from(src: &mut Cursor<'a>) -> Result<Self, UnknownTypeTag> {
295 let kind = match src.0.as_bytes().first() {
296 Some(b'+') => {
297 src.get_char();
298 TypeArgumentKind::Extends
299 }
300 Some(b'-') => {
301 src.get_char();
302 TypeArgumentKind::Super
303 }
304 _ => TypeArgumentKind::Exact,
305 };
306 Ok(Self {
307 kind,
308 signature: TypeSignature::parse_from(src)?,
309 })
310 }
311}
312
313impl Debug for TypeSignature<'_> {
314 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
315 match self {
316 TypeSignature::Primitive(ty) => write!(f, "{ty:?}"),
317 TypeSignature::Class { sig, suffix } => {
318 write!(f, "{:?}", sig)?;
319 if let Some(suffix) = suffix {
320 write!(f, ".{:?}", suffix)?;
321 }
322 Ok(())
323 }
324 TypeSignature::Type(ty) => write!(f, "{}", ty),
325 TypeSignature::Array(ty) => write!(f, "{:?}[]", ty),
326 }
327 }
328}
329
330impl Debug for ReducedClassTypeSignature<'_> {
331 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
332 write!(f, "{}", self.name)?;
333 if !self.args.is_empty() {
334 write!(f, "<")?;
335 let mut iter = self.args.iter().peekable();
336 while let Some(val) = iter.next() {
337 write!(f, "{:?}", val)?;
338 if iter.peek().is_some() {
339 write!(f, ", ")?;
340 }
341 }
342 write!(f, ">")?;
343 }
344 Ok(())
345 }
346}
347
348impl Debug for TypeArgument<'_> {
349 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
350 match self.kind {
351 TypeArgumentKind::Exact => write!(f, "{:?}", self.signature),
352 TypeArgumentKind::Extends => write!(f, "? extends {:?}", self.signature),
353 TypeArgumentKind::Super => write!(f, "? super {:?}", self.signature),
354 }
355 }
356}
357
358#[derive(PartialEq, Eq, Clone)]
360pub struct TypeParameter<'a> {
361 pub name: &'a str,
363 pub bound_class: Option<TypeSignature<'a>>,
365 pub bound_interface: Box<[TypeSignature<'a>]>,
367}
368
369impl Debug for TypeParameter<'_> {
370 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
371 write!(f, "{}", self.name)?;
372 let mut iter = self
373 .bound_class
374 .iter()
375 .chain(&self.bound_interface)
376 .peekable();
377 if iter.peek().is_some() {
378 write!(f, ": ")?;
379 }
380 while let Some(bound) = iter.next() {
381 write!(f, "{bound:?}")?;
382 if iter.peek().is_some() {
383 write!(f, " + ")?;
384 }
385 }
386 Ok(())
387 }
388}
389
390pub(crate) enum ParseTypeParamsError {
391 UnknownTypeTag(UnknownTypeTag),
392 ExpectedReference,
393}
394
395impl From<UnknownTypeTag> for ParseTypeParamsError {
396 fn from(value: UnknownTypeTag) -> Self {
397 Self::UnknownTypeTag(value)
398 }
399}
400
401pub(crate) fn parse_type_params<'a, F>(
402 contents: &mut Cursor<'a>,
403 mut f: F,
404) -> Result<(), ParseTypeParamsError>
405where
406 F: FnMut(TypeParameter<'a>),
407{
408 struct UnbakedParam<'a> {
409 name: &'a str,
410 bounds: SmallVec<[TypeSignature<'a>; 1]>,
411 }
412
413 impl<'a> From<UnbakedParam<'a>> for TypeParameter<'a> {
414 fn from(value: UnbakedParam<'a>) -> Self {
415 let mut it = value.bounds.into_iter();
416 TypeParameter {
417 name: value.name,
418 bound_class: it.next(),
419 bound_interface: it.collect(),
420 }
421 }
422 }
423
424 let mut unbaked: Option<UnbakedParam<'a>> = None;
425 while let Some(ident) = contents
426 .try_advance(|s| crate::angle_safe_rsplit(s, &[':', ';']).ok_or(()))
427 .ok()
428 .or_else(|| {
429 Some(contents.0)
430 .filter(|s| !s.is_empty())
431 .inspect(|_| contents.clear())
432 })
433 {
434 let ident = ident.strip_suffix(':').unwrap_or(ident);
435 if let Some(current) = unbaked.as_mut()
436 && ident.ends_with(';')
437 {
438 let bound = crate::parse(ident)?;
439 if !matches!(
440 bound,
441 TypeSignature::Class { .. } | TypeSignature::Type(_) | TypeSignature::Array(_)
442 ) {
443 return Err(ParseTypeParamsError::ExpectedReference);
444 }
445 current.bounds.push(bound);
446 } else {
447 if let Some(prev) = unbaked.replace(UnbakedParam {
448 name: ident,
449 bounds: SmallVec::new(),
450 }) {
451 f(prev.into());
452 }
453 }
454 }
455 if let Some(last) = unbaked {
456 f(last.into());
457 }
458 Ok(())
459}
460
461pub(crate) fn display_type_params(
462 params: &[TypeParameter<'_>],
463 f: &mut core::fmt::Formatter<'_>,
464) -> core::fmt::Result {
465 write!(f, "<")?;
466 for param in params {
467 write!(f, "{}:", param.name)?;
468 if let Some(bound) = ¶m.bound_class {
469 write!(f, "{bound}")?;
470 for bound in ¶m.bound_interface {
471 write!(f, ":{bound}")?;
472 }
473 }
474 }
475 write!(f, ">")
476}
477
478#[cfg(test)]
479mod tests {
480 use alloc::boxed::Box;
481 use smallvec::{SmallVec, smallvec};
482
483 use crate::{
484 FieldType, PrimitiveType, ReducedClassTypeSignature, TypeArgument, TypeArgumentKind,
485 TypeSignature, parse, validate_rw,
486 };
487
488 #[test]
489 fn primitives() {
490 macro_rules! primitives {
491 ($($v:ident,$l:expr),*$(,)?) => {
492 $(
493 assert_eq!(parse::<'_, FieldType<'_>>($l).unwrap(), FieldType::Primitive(PrimitiveType::$v));
494 validate_rw::<'_, FieldType<'_>>($l);
495
496 assert_eq!(parse::<'_, TypeSignature<'_>>($l).unwrap(), TypeSignature::Primitive(PrimitiveType::$v));
497 validate_rw::<'_, TypeSignature<'_>>($l);
498 )*
499 };
500 }
501
502 primitives! {
503 Byte, "B",
504 Char, "C",
505 Double, "D",
506 Float, "F",
507 Int, "I",
508 Long, "J",
509 Short, "S",
510 Boolean, "Z",
511 }
512 }
513
514 #[test]
515 fn class() {
516 assert_eq!(
517 parse::<'_, FieldType<'_>>("Ljava/lang/Object;").unwrap(),
518 FieldType::Class("java/lang/Object")
519 );
520 validate_rw::<'_, FieldType<'_>>("Ljava/lang/Object;");
521
522 assert_eq!(
523 parse::<'_, TypeSignature<'_>>("Ljava/lang/Object;").unwrap(),
524 TypeSignature::Class {
525 sig: ReducedClassTypeSignature {
526 name: "java/lang/Object",
527 args: SmallVec::new()
528 },
529 suffix: None
530 }
531 );
532 validate_rw::<'_, TypeSignature<'_>>("Ljava/lang/Object;");
533 }
534
535 #[test]
536 fn array_primitive() {
537 assert_eq!(
538 parse::<'_, FieldType<'_>>("[I").unwrap(),
539 FieldType::Array(Box::new(FieldType::Primitive(PrimitiveType::Int)))
540 );
541 validate_rw::<'_, FieldType<'_>>("[I");
542
543 assert_eq!(
544 parse::<'_, TypeSignature<'_>>("[I").unwrap(),
545 TypeSignature::Array(Box::new(TypeSignature::Primitive(PrimitiveType::Int)))
546 );
547 validate_rw::<'_, TypeSignature<'_>>("[I");
548 }
549
550 #[test]
551 fn array_primitive_2d() {
552 assert_eq!(
553 parse::<'_, FieldType<'_>>("[[I").unwrap(),
554 FieldType::Array(Box::new(FieldType::Array(Box::new(FieldType::Primitive(
555 PrimitiveType::Int
556 )))))
557 );
558 validate_rw::<'_, FieldType<'_>>("[[I");
559 assert_eq!(
560 parse::<'_, TypeSignature<'_>>("[[I").unwrap(),
561 TypeSignature::Array(Box::new(TypeSignature::Array(Box::new(
562 TypeSignature::Primitive(PrimitiveType::Int)
563 ))))
564 );
565 validate_rw::<'_, TypeSignature<'_>>("[[I");
566 }
567
568 #[test]
569 fn array_class() {
570 assert_eq!(
571 parse::<'_, FieldType<'_>>("[Ljava/lang/Object;").unwrap(),
572 FieldType::Array(Box::new(FieldType::Class("java/lang/Object")))
573 );
574 validate_rw::<'_, FieldType<'_>>("[Ljava/lang/Object;");
575 validate_rw::<'_, TypeSignature<'_>>("[Ljava/lang/Object;");
576 }
577
578 #[test]
579 fn array_class_2d() {
580 assert_eq!(
581 parse::<'_, FieldType<'_>>("[[Ljava/lang/Object;").unwrap(),
582 FieldType::Array(Box::new(FieldType::Array(Box::new(FieldType::Class(
583 "java/lang/Object"
584 )))))
585 );
586 validate_rw::<'_, FieldType<'_>>("[[Ljava/lang/Object;");
587 validate_rw::<'_, TypeSignature<'_>>("[[Ljava/lang/Object;");
588 }
589
590 #[test]
591 fn class_generics() {
592 assert_eq!(
593 parse::<'_, TypeSignature<'_>>(
594 "Ljava/util/Map<Ljava/lang/String;+Ljava/lang/Integer;>;"
595 )
596 .unwrap(),
597 TypeSignature::Class {
598 sig: ReducedClassTypeSignature {
599 name: "java/util/Map",
600 args: smallvec![
601 Some(Box::new(TypeArgument {
602 kind: TypeArgumentKind::Exact,
603 signature: TypeSignature::Class {
604 sig: ReducedClassTypeSignature {
605 name: "java/lang/String",
606 args: SmallVec::new(),
607 },
608 suffix: None
609 }
610 })),
611 Some(Box::new(TypeArgument {
612 kind: TypeArgumentKind::Extends,
613 signature: TypeSignature::Class {
614 sig: ReducedClassTypeSignature {
615 name: "java/lang/Integer",
616 args: SmallVec::new(),
617 },
618 suffix: None
619 }
620 })),
621 ]
622 },
623 suffix: None
624 }
625 );
626 validate_rw::<'_, TypeSignature<'_>>(
627 "Ljava/util/Map<Ljava/lang/String;Ljava/lang/Integer;>;",
628 );
629 }
630
631 #[test]
632 fn class_generics_any() {
633 assert_eq!(
634 parse::<'_, TypeSignature<'_>>("Ljava/util/concurrent/Future<*>;").unwrap(),
635 TypeSignature::Class {
636 sig: ReducedClassTypeSignature {
637 name: "java/util/concurrent/Future",
638 args: smallvec![None]
639 },
640 suffix: None
641 }
642 );
643 validate_rw::<'_, TypeSignature<'_>>("Ljava/util/concurrent/Future<*>;");
644 }
645
646 #[test]
647 fn class_generics_suffix() {
648 assert_eq!(
649 parse::<'_, TypeSignature<'_>>("LOuter<TT;>.Inner<TU;>;").unwrap(),
650 TypeSignature::Class {
651 sig: ReducedClassTypeSignature {
652 name: "Outer",
653 args: smallvec![Some(Box::new(TypeArgument {
654 kind: TypeArgumentKind::Exact,
655 signature: TypeSignature::Type("T"),
656 }))]
657 },
658 suffix: Some(ReducedClassTypeSignature {
659 name: "Inner",
660 args: smallvec![Some(Box::new(TypeArgument {
661 kind: TypeArgumentKind::Exact,
662 signature: TypeSignature::Type("U"),
663 }))]
664 },)
665 }
666 );
667 validate_rw::<'_, TypeSignature<'_>>("LOuter<TT;>.Inner<TU;>;");
668 }
669
670 #[test]
671 fn type_sig() {
672 assert_eq!(
673 parse::<'_, TypeSignature<'_>>("TT;").unwrap(),
674 TypeSignature::Type("T")
675 );
676 validate_rw::<'_, TypeSignature<'_>>("TT;");
677 }
678}