#java #library #shared-libraries #dynamic-library #java-class

javawithrust

以类似Rust的方式在Rust和Java之间传递函数调用

2个不稳定版本

0.2.0 2022年10月17日
0.1.0 2022年10月16日

#227 in FFI

MIT许可证

12KB

JavaWithRust-Lib

以类似Rust的方式在Rust和Java之间传递函数调用。

功能

  • 从Rust调用静态Java函数。
  • 从Java调用关联的Rust函数。
  • 将Java对象转换为Rust结构体。

限制

  • 不能从Rust调用Java方法。
  • 不能从Java调用Rust方法。

设置

创建一个动态库crate。

# Bash

cargo init . --lib
# Cargo.toml

[dependencies]
javawithrust = "0.1"
serde        = {version = "1.0", features = ["derive"]}

[lib]
crate_type = ["cdylib"]

使用

获取所需的内容。

// Rust

use javawithrust::prelude::*;

链接一个新的Java类。这将链接 JavaObject (在Rust中) 和 io.example.JavaClassName (在Java中)。

// Rust

#[jclass(io.example.JavaClassName)]
pub struct JavaObject;

链接函数。

// Rust

#[jfuncs]
impl JavaObject {

}

示例

// Rust

use javawithrust::prelude::*;

#[jclass(io.example.CustomJavaClass)]
pub struct CustomRustStruct;

#[jfuncs]
impl CustomRustStruct {

    fn hello() { // Will return `Result<(), String>`
        println!("hello");
        CustomRustStruct::world()?;
        return Ok(());
    }

    // Will call `io.example.CustomJavaClass.world()`.
    fn world();

    // Callable from java.
    fn sum(a : i32, b : i32) -> i32 { // Will return `Result<i32, String>`
        return Ok(a + b);
    }

}
// Java

package io.example;

import org.astonbitecode.j4rs.api.Instance;
import org.astonbitecode.j4rs.api.dtos.InvocationArg;
import org.astonbitecode.j4rs.api.java2rust.Java2RustUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class ConvHelper {

    public static <T> Instance<T> j2rs(T from) {
        return Java2RustUtils.createInstance(from);
    }

    @SuppressWarnings("unchecked")
    public static <T> T rs2j(Instance<T> from) {
        if (from instanceof InvocationArg) {
            InvocationArg from_ia = ((InvocationArg)from);
            if (from_ia.isSerialized()) {
                ObjectMapper mapper = new ObjectMapper();
                try {
                    return mapper.<T>readValue(from_ia.getJson(), (Class<T>)(Class.forName(from_ia.getClassName())));
                } catch (JsonProcessingException | ClassNotFoundException e) {
                    e.printStackTrace();
                    System.exit(1);
                }
            }
        }
        return Java2RustUtils.getObjectCasted(from);
    }

}
// Java

package io.example;

import org.astonbitecode.j4rs.api.Instance;
import org.astonbitecode.j4rs.api.java2rust.Java2RustUtils;

public class CustomJavaClass
{
    // Load the dynamic library.
    // The library is loaded from the same directory as the jar.
    static {
        String os=System.getProperty("os.name").toLowerCase();String path=J2RS.class.getProtectionDomain().getCodeSource().getLocation().getPath();path=path.substring(0,path.lastIndexOf("/")).replaceAll("%20"," ")+"/"+
        "robot"; // Name of the dynamic library file. `.so` and `.dll` are added automatically.
        if (os.contains("linux") || os.contains("unix") || os.contains("android")) {
            path += ".so";
        } else if (os.contains("win")) {
            path += ".dll";
        }
        else {throw new UnsatisfiedLinkError("Can not load dynamic library in unknown operating system `" + os + "`");}
        System.load(path);
    }

    public static native void hello();

    public static void world() {
        System.out.println("world!");
    }

    private static native Instance<Integer> sum(Instance<Integer> i1, Instance<Integer> i2);
    public static Integer sumFromRust(Integer a, Integer b) {
        // Convert the objects.
        return ConvHelper.rs2j(J2RS.sum(
            ConvHelper.j2rs(a),
            ConvHelper.j2rs(b)
        ));
    }

}

依赖关系

~3–4.5MB
~50K SLoC