java-signatures 0.2.1

java classfile signatures parser
Documentation
use std::fmt::{Display, Write};

use crate::{ClassType, TypeParameter};

use super::{
    BaseType, ClassSignature, FieldSignature, JavaType, MethodSignature, ReferenceType,
    SimpleClassType, ThrowsType, TypeArgument,
};

impl<'a> Display for FieldSignature<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        render_reference_type(&self.0, f)
    }
}

impl<'a> Display for ClassSignature<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        render_type_parameters(&self.type_params, f)?;
        render_class_type(&self.super_class, f)?;
        for ty in &self.super_ifaces {
            render_class_type(ty, f)?;
        }
        Ok(())
    }
}

impl<'a> Display for MethodSignature<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        render_type_parameters(&self.type_params, f)?;
        f.write_char('(')?;
        for ty in &self.parameters {
            render_java_type(ty, f)?;
        }
        f.write_char(')')?;
        match self.result {
            crate::ResultType::VoidType => f.write_char('V'),
            crate::ResultType::ValueType(ref ty) => render_java_type(ty, f),
        }?;
        for ty in &self.throws {
            f.write_char('^')?;
            match ty {
                ThrowsType::ClassType(ref ty) => render_class_type(ty, f),
                ThrowsType::TypeVariable(name) => render_type_variable(name, f),
            }?;
        }
        Ok(())
    }
}

fn render_type_variable(name: &str, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    write!(f, "T{};", name)
}

fn render_reference_type(
    ty: &ReferenceType<'_>,
    f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
    match ty {
        ReferenceType::Class(ty) => render_class_type(ty, f),
        ReferenceType::Variable(name) => render_type_variable(name, f),
        ReferenceType::Array(arr) => {
            for _ in 0..arr.dimension {
                f.write_char('[')?;
            }
            render_java_type(&arr.ty, f)
        }
    }
}

fn render_class_type(ty: &ClassType<'_>, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    f.write_char('L')?;
    render_simple_class_type(&ty.base, f)?;
    for ty in &ty.nested {
        f.write_char('.')?;
        render_simple_class_type(ty, f)?;
    }
    f.write_char(';')
}

fn render_type_parameters(
    tys: &[TypeParameter<'_>],
    f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
    if !tys.is_empty() {
        f.write_char('<')?;
        for ty in tys {
            f.write_str(ty.name)?;
            f.write_char(':')?;
            if let Some(ref ty) = ty.class_bound {
                render_reference_type(ty, f)?;
            }
            for ty in &ty.iface_bounds {
                f.write_char(':')?;
                render_reference_type(ty, f)?;
            }
        }
        f.write_char('>')?;
    }
    Ok(())
}

fn render_java_type(ty: &JavaType<'_>, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    match ty {
        JavaType::Base(ty) => f.write_char(match ty {
            BaseType::Byte => 'B',
            BaseType::Char => 'C',
            BaseType::Double => 'D',
            BaseType::Float => 'F',
            BaseType::Int => 'I',
            BaseType::Long => 'J',
            BaseType::Short => 'S',
            BaseType::Boolean => 'Z',
        }),
        JavaType::Reference(ty) => render_reference_type(ty, f),
    }
}

fn render_simple_class_type(
    ty: &SimpleClassType,
    f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
    f.write_str(ty.name)?;
    if !ty.type_args.is_empty() {
        f.write_char('<')?;
        for ty in &ty.type_args {
            match ty {
                TypeArgument::Unbounded => {
                    f.write_char('*')?;
                }
                TypeArgument::Default(ty) => {
                    render_reference_type(ty, f)?;
                }
                TypeArgument::Extends(ty) => {
                    f.write_char('+')?;
                    render_reference_type(ty, f)?;
                }
                TypeArgument::Super(ty) => {
                    f.write_char('-')?;
                    render_reference_type(ty, f)?;
                }
            }
        }
        f.write_char('>')?;
    }
    Ok(())
}