6个版本

0.1.5 2023年6月21日
0.1.4 2022年12月16日
0.1.0 2022年9月12日

120编程语言

Download history 1111/week @ 2024-04-15 1334/week @ 2024-04-22 1702/week @ 2024-04-29 1669/week @ 2024-05-06 1636/week @ 2024-05-13 116/week @ 2024-05-20 326/week @ 2024-05-27 607/week @ 2024-06-03 536/week @ 2024-06-10 436/week @ 2024-06-17 244/week @ 2024-06-24 6/week @ 2024-07-01 218/week @ 2024-07-08 181/week @ 2024-07-15 130/week @ 2024-07-22 230/week @ 2024-07-29

每月759次 下载

Apache-2.0

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

用法

通常,您可以通过以下步骤使用此库

  1. 使用 ocaml-rsocaml_gen 宏对您的类型和函数进行注解。
  2. 创建一个 main.rs 文件,如上所示生成您的绑定文件 bindings.ml
  3. 使用 ocaml-rs crate导出OCaml将使用的静态库。
  4. 在您的crate中添加一个 dune 文件,以构建Rust静态库以及OCaml绑定。(提示:在dune文件中使用 (mode promote) 以使生成的绑定文件位于文件夹中。)
  5. 可选地,在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,即使t1Thing<String>的别名(这是主要危险,请参见此跟踪问题)。
  • 如果尝试为同一泛型类型的两个实例创建别名(例如,t1Thing<usize>的别名,而t2Thing<String>的别名),则不会工作(绑定生成将引发错误)。

依赖项

~3MB
~60K SLoC