jvm 0.3.0

Core abstractions and runtime services for embeddable JVM implementations
Documentation
use alloc::{boxed::Box, string::String, vec::Vec};

use bytemuck::cast_vec;

use crate::{Array, ClassInstanceRef, Result, class_definition::ClassDefinition, class_instance::ClassInstance, jvm::Jvm};

pub struct JavaLangClass;

impl JavaLangClass {
    pub async fn from_rust_primitive(jvm: &Jvm, name: &str) -> Result<Box<dyn ClassInstance>> {
        let mut java_class = jvm.new_class("java/lang/Class", "()V", ()).await?;
        let mut name_bytes = jvm.instantiate_array("B", name.len()).await?;
        let bytes: Vec<i8> = cast_vec(name.as_bytes().to_vec());
        jvm.store_array(&mut name_bytes, 0, bytes).await?;
        jvm.put_field(&mut java_class, "java/lang/Class", "nameBytes", "[B", name_bytes).await?;

        Ok(java_class)
    }

    #[allow(clippy::borrowed_box)]
    pub async fn name(jvm: &Jvm, this: &Box<dyn ClassInstance>) -> Result<String> {
        let name_bytes: ClassInstanceRef<Array<i8>> = jvm.get_field(this, "java/lang/Class", "nameBytes", "[B").await?;
        let len = jvm.array_length(&name_bytes).await?;
        let name_bytes_vec: Vec<i8> = jvm.load_array(&name_bytes, 0, len).await?;
        match String::from_utf8(cast_vec(name_bytes_vec)) {
            Ok(name) => Ok(name),
            Err(_) => Err(jvm.exception("java/lang/NoClassDefFoundError", "invalid class name").await),
        }
    }

    #[allow(clippy::borrowed_box)]
    pub async fn to_rust_class(jvm: &Jvm, this: &Box<dyn ClassInstance>) -> Result<Box<dyn ClassDefinition>> {
        let class_name = Self::name(jvm, this).await?;
        if let Some(class) = jvm.get_class(&class_name) {
            Ok(class.definition)
        } else {
            Err(jvm.exception("java/lang/NoClassDefFoundError", &class_name).await)
        }
    }

    pub async fn from_rust_class(
        jvm: &Jvm,
        rust_class: Box<dyn ClassDefinition>,
        class_loader: Option<Box<dyn ClassInstance>>,
    ) -> Result<Box<dyn ClassInstance>> {
        let mut java_class = jvm.new_class("java/lang/Class", "()V", ()).await?;

        let class_name = rust_class.name();
        let mut name_bytes = jvm.instantiate_array("B", class_name.len()).await?;
        let bytes: Vec<i8> = cast_vec(class_name.into_owned().into_bytes());
        jvm.store_array(&mut name_bytes, 0, bytes).await?;
        jvm.put_field(&mut java_class, "java/lang/Class", "nameBytes", "[B", name_bytes).await?;

        jvm.put_field(&mut java_class, "java/lang/Class", "classLoader", "Ljava/lang/ClassLoader;", class_loader)
            .await?;

        Ok(java_class)
    }

    #[allow(clippy::borrowed_box)]
    pub async fn class_loader(jvm: &Jvm, this: &Box<dyn ClassInstance>) -> Result<Option<Box<dyn ClassInstance>>> {
        jvm.get_field(this, "java/lang/Class", "classLoader", "Ljava/lang/ClassLoader;").await
    }
}