6个版本
0.1.5 | 2023年6月21日 |
---|---|
0.1.4 | 2022年12月16日 |
0.1.0 | 2022年9月12日 |
120 在 编程语言 中
每月759次 下载
27KB
530 行
OCaml-gen
这个crate提供了OCaml绑定的自动生成。有关更多信息,请参阅rustdoc。
示例
以下是一个生成一些绑定的示例。创建一个 main.rs
如下
use ocaml_gen::prelude::*;
// Some Rust code you have:
#[derive(ocaml::FromValue, ocaml::IntoValue, ocaml_gen::CustomType)]
pub struct SomeType {
pub a: u8,
}
#[ocaml_gen::func]
#[ocaml::func]
fn create_some_type() -> SomeType {
SomeType { a: 42 }
}
fn main() {
// initialize your environment
let env = &mut Env::default();
// choose where you want to write the bindings
let w = &mut std::io::stdout();
// you can declare modules
decl_module!(w, env, "Types", {
// and types
decl_type!(w, env, SomeType => "t");
});
decl_module!(w, env, "Functions", {
// and functions
decl_func!(w, env, create_some_type => "create");
});
}
注意,通过 decl_func!
导入的底层函数实际上是 caml_of_numeral_to_ocaml
,它是由带注解的宏 ocaml_gen::func
创建的。因此,要么你的函数在作用域内,要么导入所有内容(例如,use path::*
),或者直接导入派生函数(例如,use path::caml_of_numeral_to_ocaml
)。
生成的OCaml绑定应如下所示
module Types = struct
type nonrec t
end
module Functions = struct
val create : unit -> Types.t
end
用法
通常,您可以通过以下步骤使用此库
- 使用
ocaml-rs
和ocaml_gen
宏对您的类型和函数进行注解。 - 创建一个
main.rs
文件,如上所示生成您的绑定文件bindings.ml
。 - 使用
ocaml-rs
crate导出OCaml将使用的静态库。 - 在您的crate中添加一个
dune
文件,以构建Rust静态库以及OCaml绑定。(提示:在dune文件中使用(mode promote)
以使生成的绑定文件位于文件夹中。) - 可选地,在CI中强制检查提升的绑定文件是否正确。
您可以在 test/ 文件夹中看到这些步骤的示例。(尽管我们出于测试目的没有使用dune提升文件。)
注解
为了使ocaml-gen能够理解如何从您的类型和函数生成OCaml绑定,您必须使用ocaml-gen的宏对其进行注解。
为了允许在结构体上生成绑定,请使用 ocaml_gen::Struct
#[ocaml_gen::Struct]
struct MyType {
// ...
}
为了允许在枚举上生成绑定,请使用ocaml_gen::Enum
#[ocaml_gen::Enum]
enum MyType {
// ...
}
为了允许在函数上生成绑定,请使用ocaml_gen::func
#[ocaml_gen::func]
#[ocaml::func] // if you use the crate ocaml-rs' macro, it must appear after
pub fn your_function(arg1: String) {
//...
}
为了允许在自定义类型上生成绑定,请使用ocaml_gen::CustomType
#[ocaml_gen::CustomType]
struct MyCustomType {
// ...
}
绑定生成
要生成绑定,您必须创建一个main.rs
文件,使用ocaml_gen
crate函数来布局绑定.ml
文件的外观。首先,需要导入您想要为绑定生成代码的类型和函数,以及ocaml_gen
宏。
use ocaml_gen::prelude::*;
use your_crate::*;
然后,可以使用decl_module!
来声明模块。
let env = &mut Env::default();
let w = &mut std::io::stdout();
decl_module!(w, env, "T1", {
decl_module!(w, env, "T2", {
decl_type!(w, env, SomeType);
});
});
decl_module!(w, env, "T3", {
decl_type!(w, env, SomeOtherType);
});
您可以通过简单地添加箭头来重命名类型和函数。
decl_type!(w, env, SomeType => "t");
您还可以通过首先声明泛型类型参数(您必须为所有泛型类型重复使用这些参数)来声明泛型类型。
decl_fake_generic!(T1, 0); // danger:
decl_fake_generic!(T2, 1); // make sure you
decl_fake_generic!(T3, 2); // increment these correctly
decl_type!(w, env, TypeWithOneGenericType<T1>);
decl_type!(w, env, ThisOneHasTwo<T1, T2>);
decl_type!(w, env, ThisOneHasThreeOfThem<T1, T2, T3>);
您还可以使用decl_type_alias!
宏来创建类型别名,但它是高度实验性的。它存在一些问题:
- 别名在其声明模块的当前作用域之外不工作(这通常是您想要的)。
- 别名忽略类型参数的实例化。这意味着它可能会将
Thing<usize>
重命名为t1
,即使t1
是Thing<String>
的别名(这是主要危险,请参见此跟踪问题)。 - 如果尝试为同一泛型类型的两个实例创建别名(例如,
t1
是Thing<usize>
的别名,而t2
是Thing<String>
的别名),则不会工作(绑定生成将引发错误)。
依赖项
~3MB
~60K SLoC