使用Java调用Rust

概括简述

我整理了使用JNA调用Rust的方法。

备前。

首先,将JNA库添加到maven或build.sbt文件中。

scalaVersion := "2.13.6"
libraryDependencies += "net.java.dev.jna" % "jna" % "5.9.0"
libraryDependencies += "net.java.dev.jna" % "jna-platform" % "5.9.0"

使用Java调用Rust

你好世界的程序

使用 Rust 创建共享库

我将创建一个如下的程序。

// #[no_mangle]を指定すると、コンパイル時にメソッド名を変更されないようすることができます。
#[no_mangle]
fn main() {
    println!("Hello, world!");
}

然后,在Mac中,使用以下命令创建共享库。

rustc main.rs --crate-type=dylib

※ 实际上,使用 cargo 进行构建似乎更加实用和优秀。

Java方面的实现

import com.sun.jna.Library;
import com.sun.jna.Native;

public class JnaHoge {
    public interface HogeInterface extends Library {
        HogeInterface INSTANCE = Native.load("main", HogeInterface.class);

        void main();
    }

    public static void main(String[] args) {
        System.out.println("started");
        HogeInterface.INSTANCE.main();
        System.out.println("finished");
    }
}

目录树

以下是main.rs、libmain.dylib和JnaHoge.java的目录结构。

.
├── build.sbt
├── libmain.dylib
├── main.rs
├── project
│   ├── build.properties
|
├── src
│   ├── main
│   │   ├── java
│   │   │   └── JnaHoge.java
│   │   ├── resources
│   │   └── scala
│   └── test
│       └── scala

执行结果

对于sbt的情况,可以通过sbt “runMain JnaHoge”来执行。

执行结果:

started
Hello, world!
finished

使用Rust创建共享库,并从Java中调用的示例代码。

在Rust的std::os::raw模块中定义的类型,保证与C的特定类型具有相同的表达方式。
因此,当创建从其他语言调用的函数时,应该在参数和返回值中使用std::os::raw的类型。

传递一个整型,获取一个整型值

use std::os::raw::c_int;

#[no_mangle]
fn plus_one(x: c_int) -> c_int {
    x + 1
}
import com.sun.jna.Library;
import com.sun.jna.Native;

public class JnaHoge {
    public interface HogeInterface extends Library {
        HogeInterface INSTANCE = Native.load("main", HogeInterface.class);

        int plus_one(int x);
    }

    public static void main(String[] args) {
        System.out.println("started");
        int x = HogeInterface.INSTANCE.plus_one(1);
        System.out.println(x);
        System.out.println("finished");
    }
}

运行结果:

started
2
finished

通过传递String类型,获取一个String类型的值。

use std::os::raw::c_char;
use std::ffi::CString;

#[no_mangle]
unsafe fn append_hoge(cs: *mut c_char) -> *mut c_char {
    let mut cs_string = CString::from_raw(cs).into_string().expect("Failed to create String");
    cs_string.push_str("hoge");
    CString::new(cs_string).expect("Failed to create CString").into_raw()
}
import com.sun.jna.Library;
import com.sun.jna.Native;

public class JnaHoge {
    public interface HogeInterface extends Library {
        HogeInterface INSTANCE = Native.load("main", HogeInterface.class);

        String append_hoge(String str);
    }

    public static void main(String[] args) {
        System.out.println("started");
        String str = HogeInterface.INSTANCE.append_hoge("ほげ_");
        System.out.println(str);
        System.out.println("finished");
    }
}

执行结果:

started
ほげ_hoge
finished

通过传递一个数组来获取一个数组。

use std::os::raw::c_int;

#[no_mangle]
unsafe fn add_one(array: *mut c_int, new_array: *mut c_int) {
    let new_slice = std::slice::from_raw_parts_mut(new_array, 3);
    let slice = std::slice::from_raw_parts(array, 3);
    new_slice[0] = slice[0] * 10;
    new_slice[1] = slice[1] * 10;
    new_slice[2] = slice[2] * 10;
}
import com.sun.jna.Library;
import com.sun.jna.Native;

public class JnaHoge {
    public interface HogeInterface extends Library {
        HogeInterface INSTANCE = Native.load("main", HogeInterface.class);

        void add_one(int[] array, int[] newArray);
    }

    public static void main(String[] args) {
        System.out.println("started");

        int[] array = {4, 5, 6};
        int[] newArray = new int[3];
        HogeInterface.INSTANCE.add_one(array, newArray);

        System.out.println(newArray[0]);
        System.out.println(newArray[1]);
        System.out.println(newArray[2]);
        System.out.println("finished");
    }
}

执行结果:

started
40
50
60
finished

提供一个结构体以获得Java类

use std::os::raw::c_int;
use std::os::raw::c_char;

#[repr(C)] // C言語の構造体と互換性を持たせるようにするアトリビュート
struct Person {
    age: c_int,
    name: *mut c_char
}

#[no_mangle]
unsafe fn set_age(person: *mut Person) -> *mut Person {
    (*person).age = 25;
    person
}
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Structure;


public class JnaHoge {
    public interface HogeInterface extends Library {
        HogeInterface INSTANCE = Native.load("main", HogeInterface.class);

        @Structure.FieldOrder({"age", "name"})
        class Person extends Structure {
            public int age;
            public String name;

            void setName(String str) {
                name = str;
            }
        }


        Person set_age(Person person);
    }

    public static void main(String[] args) {
        System.out.println("started");
        HogeInterface.Person person = new HogeInterface.Person();
        person.setName("パターソン");

        HogeInterface.Person newPerson = HogeInterface.INSTANCE.set_age(person);
        System.out.println(person.name + "(" + person.age + ")");
        System.out.println(newPerson.name + "(" + newPerson.age + ")");
        System.out.println("finished");
    }
}

执行结果:

started
パターソン(25)
パターソン(25)
finished

bannerAds