gpt4 book ai didi

java - 使用 JNA 在 Clojure 中按值获取和传递结构

转载 作者:搜寻专家 更新时间:2023-10-31 19:55:02 29 4
gpt4 key购买 nike

我有一个 C API,我想通过 JNA API 在 Clojure 中使用它。下面的示例可以最好地说明我的问题。假设我在库中有这个 C 代码:

typedef struct {
int foo;
int bar;
double baz;
} MyStruct;

MyStruct createStruct() {
MyStruct myStruct;
myStruct.foo = 3;
myStruct.bar = 4;
myStruct.baz = 3.14;

return myStruct;
}

double addStruct(MyStruct myStruct) {
return myStruct.foo + myStruct.bar + myStruct.baz;
}

在这个例子中,我想调用createStruct,然后将该结果传递给addStruct。这里的重点是 MyStruct 作为返回类型和参数按值传递。我在任何时候都不需要实际读取 MyStruct 中字段的值。

此外,在我的系统中,原生函数是这样包装的:

; `quux` is defined in `some-lib` and returns an `int`
(let [fn- (com.sun.jna.Function/getFunction "some-lib" "quux")]
(fn [& args]
(.invoke fn- Integer (to-array args))))

目标是获取一个类型来替代上面的 Integer,它将把 MyStruct 包装成一个值。

我找到的唯一涵盖此主题的资源是 this article ,但它只讨论如何通过引用传递结构。

鉴于此,以下是我尝试采用的不同方法来解决此问题:

  1. 创建一个继承自Structure的类,也就是JNA的built-in mechanism for creating and using structs .根据该页面上的信息,我尝试仅使用 Clojure 创建以下类:

    class MyStruct extends Structure implements Structure.ByValue {
    int foo;
    int bar;
    double baz;
    }

    deftype不适用于这种场景,因为该类需要继承抽象类Structure,而gen-class不适用无法工作,因为该类需要具有公共(public)非静态字段 foobarbaz

    据我所知,没有任何标准的 Clojure Java 互操作工具可以创建上述类。

  2. 创建一个继承自 Structure 的类并覆盖结构字段的 getter/setter 方法。由于 gen-class 是(我相信)唯一允许直接继承的 Clojure 构造,并且它不支持多个公共(public)非静态字段,下一个替代方案是根本不使用字段. Looking at the Structure abstract class documentation ,似乎有可能使用“虚拟”结构字段的覆盖组合,这样它实际上从不同的源(such as the state field from gen-class)获取和设置数据。查看文档,似乎重写 readFieldwriteField 和其他一些方法可能具有预期效果,但我不清楚如何通过阅读文档来做到这一点,我在网上找不到任何类似的例子。

  3. 使用不同的存储类别。 JNA 有无数类用于包装 native 类型。我想知道,除了定义和使用 Structure 类,我是否可以使用另一个可以采用任意位数的通用类(比如 Integer 可以容纳任何东西这是 4 位宽,不管源“实际上”是什么类型)。例如,是否可以说函数返回长度为 16 的字节数组(因为 sizeof(MyStruct) 是 16)?在实现 NativeMapped 的容器类中包装一个固定大小的数组怎么样? ?我找不到有关如何操作的示例。

最佳答案

Clojure 实际上嵌入了 ASM 的 fork 版本,用于生成和加载 JVM 字节码。

在此库之上,我构建了小型 DSL(不完整且可能已损坏),它允许使用类似 Java 的语法创建任意 Java 类。目前,它只是一个 GitHub gist ,并且只支持扩展类、实现接口(interface)、添加调用父类(super class)构造函数的构造函数和字段。

下面是上述问题的解决方案,使用这个 DSL:

(def-class MyStruct :extends    com.sun.jna.Structure
:implements [com.sun.jna.Structure$ByValue]
; Declare all the constructors, which just forward their
; arguments to the constructors of com.sun.jna.Structure
(com.sun.jna.Structure [])
(com.sun.jna.Structure [com.sun.jna.TypeMapper])
(com.sun.jna.Structure [Integer])
(com.sun.jna.Structure [Integer com.sun.jna.TypeMapper])
(com.sun.jna.Structure [com.sun.jna.Pointer])
(com.sun.jna.Structure [com.sun.jna.Pointer Integer])
(com.sun.jna.Structure [com.sun.jna.Pointer Integer com.sun.jna.TypeMapper])

; Declare the fields of the struct
^Integer foo
^Integer bar
^Double baz)

现在,我可以执行以下操作:

(defn createStruct [& args]
(let [fn- (com.sun.jna.Function/getFunction "some-lib" "createStruct")]
(.invoke fn- MyStruct (to-array args))))

(defn addStruct [& args]
(let [fn- (com.sun.jna.Function/getFunction "some-lib" "addStruct")]
(.invoke fn- Double (to-array args))))

(addStruct (createStruct))
; => 10.14

关于java - 使用 JNA 在 Clojure 中按值获取和传递结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24976711/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com