# Basic Rust and C++ InterOp

Interoperability between different programming languages is a common requirement in many software projects. In this article, we will explore how to interoperate between the Rust and C++ programming languages, allowing you to use the strengths of both languages in your projects.

Rust is a modern, statically-typed programming language that offers low-level control and concurrency without sacrificing safety and reliability. C++ is a high-performance, low-level programming language that is widely used in systems programming and other performance-critical applications.

To interop between Rust and C++, we will use the `rust-cpython` crate, which provides safe and idiomatic Rust bindings for the Python C API. This crate allows you to call Rust functions from C++ and vice versa, making it easy to integrate Rust and C++ code in your projects.

To begin, we will add the `rust-cpython` crate to our `Cargo.toml` file as a dependency.

```rust
[dependencies]
rust-cpython = "0.4.0"
```

Next, we will import the `rust-cpython` crate and the `Python` and `PyObject` types in our Rust code.

```rust
use rust_cpython::{Python, PyObject};
```

Now, we can define a Rust function that we want to call from C++. This function must take a `&Python` argument and return a `PyObject`. In this example, we will define a simple `add` function that takes two `i32` arguments and returns their sum.

```rust
fn add(py: &Python, a: i32, b: i32) -> PyObject {
    // Return the sum of the two arguments.
    (a + b).to_py_object(py)
}
```

To call this function from C++, we will use the `rust_cpython::PyModule` class to define a Rust module that exports the `add` function. We will then use the `PyImport_AppendInittab` function from the Python C API to register the Rust module and make it available to C++.

```rust
rust_cpython::PyModule::new(py, "rust")
    .add("add", py_fn!(py, add(a: i32, b: i32)))
    .register()
    .unwrap();

// Register the Rust module in the Python interpreter.
PyImport_AppendInittab("rust", rust_cpython::init_module);
```

Now, we can call the `add` function from C++ using the Python C API. To do this, we will import the `Python.h` header, which provides declarations for the Python C API. We will then use the `PyImport_ImportModule` function to import the Rust module, the `PyObject_GetAttrString` function to get the `add` function from the module, and the `PyObject_CallObject` function to call the `add` function with the desired arguments.

```cpp
#include <Python.h>

// Import the Rust module.
PyObject* module = PyImport_ImportModule("rust");

// Get the `add` function from the module.
PyObject* func = PyObject_GetAttrString(module, "add");

// Call the `add` function with the desired arguments.
PyObject* result = PyObject_CallObject(func, Py_BuildValue("(ii)", 1, 2));

// Print the result.
printf("%d\n", PyLong_AsLong(result));
```

This code will print `3` to the standard output, indicating that the `add` function was called successfully from C++.

In addition to calling Rust functions from C++, you can also call C++ functions from Rust using the `rust-cpython` crate. To do this, you will need to define the C++ function using the `extern "C"` keyword, which ensures that the function has a C-compatible signature.

For example, if you have a C++ function called `multiply` that takes two `int` arguments and returns their product, you can define the function in a header file as follows:

```cpp
#ifndef MULTIPLY_H
#define MULTIPLY_H

#ifdef __cplusplus
extern "C" {
#endif

// Define the `multiply` function.
int multiply(int a, int b);

#ifdef __cplusplus
}
#endif

#endif
```

You can then implement the `multiply` function in a C++ source file and compile it as a shared library.

```cpp
#include "multiply.h"

// Implement the `multiply` function.
int multiply(int a, int b) {
    return a * b;
}
```

Once you have compiled the shared library, you can call the `multiply` function from Rust using the `rust-cpython::PyCapsule` class. This class allows you to create a Rust wrapper for a C++ function, which you can then call from Rust using the `call` method.

```rust
// Import the `PyCapsule` type from the `rust-cpython` crate.
use rust_cpython::PyCapsule;

// Define a Rust wrapper for the `multiply` function.
struct Multiply {
    multiply: PyCapsule,
}

impl Multiply {
    fn new(py: &Python) -> Self {
        // Load the `multiply` shared library.
        let multiply = PyCapsule::new(py, "multiply", "multiply").unwrap();

        Self { multiply }
    }

    // Define a method that calls the `multiply` function.
```

To call the `multiply` function from Rust, you can define a method on the `Multiply` struct that uses the `call` method of the `PyCapsule` to call the C++ function. This method takes the arguments for the function as a `PyTuple` and returns the result as a `PyObject`.

```rust
impl Multiply {
    // ...

    // Define a method that calls the `multiply` function.
    fn multiply(&self, py: &Python, a: i32, b: i32) -> PyObject {
        // Call the `multiply` function with the desired arguments.
        self.multiply
            .call(py, (a, b).to_py_tuple(py))
            .unwrap()
    }
}
```

Now, you can use the `Multiply` struct to call the `multiply` function from your Rust code.

```rust
let multiply = Multiply::new(py);

// Call the `multiply` function and print the result.
println!("{}", multiply.multiply(py, 2, 3).extract::<i32>(py).unwrap());
```

This code will print `6` to the standard output, indicating that the `multiply` function was called successfully from Rust.

In summary, the `rust-cpython` crate provides a convenient and safe way to interop between Rust and C++. By using this crate, you can call Rust functions from C++ and C++ functions from Rust, allowing you to use the strengths of both languages in your projects.
