tizoc / ocaml-interop

OCaml<->Rust FFI with an emphasis on safety.
MIT License
135 stars 22 forks source link

Investigate the possibility of splitting the logic to startup/shutdown the OCaml runtime to another crate #38

Open tizoc opened 3 years ago

tizoc commented 3 years ago

Related to #34 and the idea @mrmr1993 had (with proof-of-concept in #36).

Will require some synchronization with @zshipko to keep things compatible with ocaml-rs.

From the point of view of things being different when the program is Rust-driven from when the program is OCaml-driven, the split makes sense, because the dependencies and requirements are not the same. When ocaml-interop/ocaml-rs are used to write Rust code that will be called from an OCaml program, the startup and shutdown of the OCaml runtime is already handled by the OCaml program, and doesn't make sense for the Rust code to do it. But when the driving program is a Rust program, it must initialize (and shutdown) the OCaml runtime by itself.

The solution I am thinking about is to remove from ocaml-interop the OCamlRuntime::init_persistent()/init() methods and the implementation of the Drop trait for OCamlRuntime. Then in a new crate, implement a new type that will serve as the handle for the runtime initialization, which will have this Drop implementatios, the init*() methods, and a way to borrow from it a &mut OCamlRuntime.

So this (from the ocaml-interop example in the docs):

fn main() {
    // IMPORTANT: the OCaml runtime has to be initialized first.
    let mut cr = OCamlRuntime::init();
    let first_n = twice(&mut cr, 5);
    let bytes1 = "000000000000000".to_owned();
    let bytes2 = "aaaaaaaaaaaaaaa".to_owned();
    println!("Bytes1 before: {}", bytes1);
    println!("Bytes2 before: {}", bytes2);
    let (result1, result2) = increment_bytes(&mut cr, bytes1, bytes2, first_n);
    println!("Bytes1 after: {}", result1);
    println!("Bytes2 after: {}", result2);
    // `OCamlRuntime`'s `Drop` implementation will perform the necessary cleanup
    // to shutdown the OCaml runtime.
}

will look like this

fn main() {
    // IMPORTANT: the OCaml runtime has to be initialized first.
    let mut cr = ocaml_runtime::OCamlRuntimeInit::start();
    // Assuming we can Deref OCamlRuntimeInit into an OCamlRuntime
    // alternatively a new method will be added to do that.
    let first_n = twice(&mut cr, 5);
    let bytes1 = "000000000000000".to_owned();
    let bytes2 = "aaaaaaaaaaaaaaa".to_owned();
    println!("Bytes1 before: {}", bytes1);
    println!("Bytes2 before: {}", bytes2);
    let (result1, result2) = increment_bytes(&mut cr, bytes1, bytes2, first_n);
    println!("Bytes1 after: {}", result1);
    println!("Bytes2 after: {}", result2);
    // `OCamlRuntimeInit`'s `Drop` implementation will perform the necessary cleanup
    // to shutdown the OCaml runtime.
}
tizoc commented 3 years ago

Some things to keep in mind here: https://github.com/tezedge/ocaml-interop/issues/39