rusty-jvm 0.5.0

An implementation of a Java Virtual Machine (JVM).
Documentation
use crate::vm::error::Result;
use crate::vm::method_area::method_area::with_method_area;

pub(crate) struct InstanceChecker {}

impl InstanceChecker {
    pub fn checkcast(class_cast_from: &str, class_cast_to: &str) -> Result<bool> {
        let (class_cast_from, class_cast_to) =
            Self::try_unwrap_arrays(class_cast_from, class_cast_to);

        if let Some(base_of) = Self::is_base_of(class_cast_to, class_cast_from) {
            return Ok(base_of);
        }

        let class = with_method_area(|method_area| method_area.get(class_cast_to))?;
        if class.is_interface() {
            if let Some(implements) = Self::implements(class_cast_to, class_cast_from) {
                return Ok(implements);
            }
        }

        Ok(false)
    }

    fn try_unwrap_arrays<'a>(first: &'a str, second: &'a str) -> (&'a str, &'a str) {
        fn unwrap_descriptor(descr: &str) -> &str {
            if descr.starts_with('L') {
                &descr[1..descr.len() - 1]
            } else {
                descr
            }
        }

        if first.starts_with('[') && second.starts_with('[') {
            Self::try_unwrap_arrays(&first[1..], &second[1..])
        } else {
            let first = unwrap_descriptor(first);
            let second = unwrap_descriptor(second);
            (first, second)
        }
    }

    fn is_base_of(base: &str, child: &str) -> Option<bool> {
        if base == child {
            return Some(true);
        }

        let class = with_method_area(|method_area| method_area.get(child)).ok()?;
        let class_name = class.parent().clone()?;

        Self::is_base_of(base, &class_name)
    }

    fn implements(interface: &str, implementor: &str) -> Option<bool> {
        let class_implementor =
            with_method_area(|method_area| method_area.get(implementor)).ok()?;

        let interfaces = class_implementor.interfaces();
        for interface_name in interfaces.iter() {
            if interface_name == interface {
                return Some(true);
            }

            if let Some(implements) = Self::implements(interface, interface_name) {
                return Some(implements);
            }
        }

        let class_name = class_implementor.parent().clone()?;

        Self::implements(interface, &class_name)
    }
}