ocaml/lib.rs
1#![deny(missing_docs)]
2#![cfg_attr(feature = "no-std", no_std)]
3#![allow(clippy::missing_safety_doc)]
4
5//! [ocaml-rs](https://github.com/zshipko/ocaml-rs/) is a library for directly interacting with the C OCaml runtime, in Rust.
6//!
7//! The OCaml manual chapter [Interfacing C with OCaml](https://caml.inria.fr/pub/docs/manual-ocaml/intfc.html) does
8//! a great job of explaining low-level details about how to safely interact with the OCaml runtime. This crate aims to
9//! be a slightly higher-level of abstraction, with minimal added overhead.
10//!
11//! ## Getting started
12//!
13//! Take a look at the [ocaml-rust-starter](http://github.com/zshipko/ocaml-rust-starter) project for a basic example to help get started with `ocaml-rs`.
14//!
15//! ## Examples
16//!
17//! ```rust,no_run
18//! use ocaml::FromValue;
19//!
20//! // Automatically derive `ToValue` and `FromValue`
21//! #[cfg(feature = "derive")]
22//! #[derive(ocaml::ToValue, ocaml::FromValue)]
23//! #[ocaml::sig("{name: string; i: int}")]
24//! struct Example {
25//! name: String,
26//! i: ocaml::Int,
27//! }
28//!
29//! #[cfg(feature = "derive")]
30//! #[ocaml::func]
31//! #[ocaml::sig("example -> example")]
32//! pub fn incr_example(mut e: Example) -> Example {
33//! e.i += 1;
34//! e
35//! }
36//!
37//! #[cfg(feature = "derive")]
38//! #[ocaml::func]
39//! #[ocaml::sig("int -> int * int * int")]
40//! pub fn build_tuple(i: ocaml::Int) -> (ocaml::Int, ocaml::Int, ocaml::Int) {
41//! (i + 1, i + 2, i + 3)
42//! }
43//!
44//! /// A name for the garbage collector handle can also be specified:
45//! #[cfg(feature = "derive")]
46//! #[ocaml::func(my_gc_handle)]
47//! #[ocaml::sig("unit -> string")]
48//! pub unsafe fn my_string() -> ocaml::Value {
49//! ocaml::Value::string("My string")
50//! }
51//!
52//! #[cfg(feature = "derive")]
53//! #[ocaml::func]
54//! #[ocaml::sig("float array -> float")]
55//! pub fn average(arr: ocaml::Array<f64>) -> Result<f64, ocaml::Error> {
56//! let mut sum = 0f64;
57//!
58//! for i in 0..arr.len() {
59//! sum += arr.get_f64(i)?;
60//! }
61//!
62//! Ok(sum / arr.len() as f64)
63//! }
64//!
65//! // A `native_func` must take `ocaml::Value` for every argument or `f64` for
66//! // every unboxed argument and return an `ocaml::Value` (or `f64`).
67//! // `native_func` has minimal overhead compared to wrapping with `func`
68//! #[cfg(feature = "derive")]
69//! #[ocaml::native_func]
70//! #[ocaml::sig("int -> int")]
71//! pub unsafe fn incr(value: ocaml::Value) -> ocaml::Value {
72//! let i = isize::from_value(value);
73//! ocaml::Value::int(i + 1)
74//! }
75//!
76//! // This is equivalent to:
77//! #[no_mangle]
78//! pub unsafe extern "C" fn incr2(value: ocaml::Value) -> ocaml::Value {
79//! ocaml::body!(gc: {
80//! let i = isize::from_value(value);
81//! ocaml::Value::int( i + 1)
82//! })
83//! }
84//!
85//! // `ocaml::native_func` is responsible for:
86//! // - Ensures that #[no_mangle] and extern "C" are added, in addition to wrapping
87//! // - Wraps the function body using `ocaml::body!`
88//!
89//! // Finally, if your function is marked [@@unboxed] and [@@noalloc] in OCaml then you can avoid
90//! // boxing altogether for f64 arguments using a plain C function and a bytecode function
91//! // definition:
92//! #[no_mangle]
93//! pub extern "C" fn incrf(input: f64) -> f64 {
94//! input + 1.0
95//! }
96//!
97//! #[cfg(feature = "derive")]
98//! #[ocaml::bytecode_func]
99//! pub fn incrf_bytecode(input: f64) -> f64 {
100//! incrf(input)
101//! }
102//! ```
103//!
104//! The OCaml stubs would look like this:
105//!
106//! ```ocaml
107//! type example = {
108//! name: string;
109//! i: int;
110//! }
111//!
112//! external incr_example: example -> example = "incr_example"
113//! external build_tuple: int -> int * int * int = "build_tuple"
114//! external average: float array -> float = "average"
115//! external incr: int -> int = "incr"
116//! external incr2: int -> int = "incr2"
117//! external incrf: float -> float = "incrf_bytecode" "incrf" [@@unboxed] [@@noalloc]
118//! ```
119//!
120//! Excluding the `incrf` example, these can also be automatically generated using [ocaml-build](https://github.com/zshipko/ocaml-rs/blob/master/build/README.md)
121//!
122//! For more information see the [ocaml-rs book](https://zshipko.github.io/ocaml-rs)
123
124#[cfg(all(feature = "link", feature = "no-std"))]
125std::compile_error!("Cannot use link and no-std features");
126
127/// The `sys` module contains the low-level implementation of the OCaml runtime
128pub use ocaml_sys as sys;
129
130#[cfg(feature = "derive")]
131pub use ocaml_derive::{
132 ocaml_bytecode_func as bytecode_func, ocaml_func as func, ocaml_native_func as native_func,
133 ocaml_sig as sig, FromValue, ToValue,
134};
135
136#[macro_use]
137mod macros;
138
139mod conv;
140mod error;
141mod pointer;
142mod tag;
143mod types;
144mod util;
145mod value;
146
147/// Rooted values
148pub mod root;
149
150/// Functions for interacting with the OCaml runtime
151pub mod runtime;
152
153/// Custom types, used for allocating Rust values owned by the OCaml garbage collector
154pub mod custom;
155
156pub use crate::custom::Custom;
157pub use crate::error::{CamlError, Error};
158pub use crate::pointer::Pointer;
159pub use crate::runtime::Runtime;
160pub use crate::runtime::*;
161pub use crate::tag::Tag;
162pub use crate::types::{bigarray, Array, List, Seq};
163pub use crate::value::{FromValue, Raw, ToValue, Value};
164
165/// OCaml `float`
166pub type Float = f64;
167
168/// Integer type that converts to OCaml `int`
169pub type Int = sys::Intnat;
170
171/// Unsigned integer type that converts to OCaml `int`
172pub type Uint = sys::Uintnat;
173
174/// Wraps `sys::COMPILER` as `std::process::Command`
175#[cfg(not(any(feature = "no-std", feature = "without-ocamlopt")))]
176pub fn ocamlopt() -> std::process::Command {
177 std::process::Command::new(sys::COMPILER)
178}