Skip to content

Calling Rust code from Python

Posted on:December 10, 2022

Calling Rust code from Python is a powerful way to combine the performance and safety of Rust with the simplicity and ease of use of Python. In this post, we will explore how to call Rust code from Python, and discuss the benefits of using these two languages together.

Table of contents

Open Table of contents

Installing Rust and Creating a New Project

The first step in calling Rust code from Python is to install Rust on your computer. You can do this by following the instructions on the Rust website rust-lang. Once Rust is installed, you can create a new Rust project by running the following command:

cargo new rust-python-project

This will create a new directory named rust-python-project with the necessary files and directories for a Rust project.

Compiling the Rust Code

Next, we need to compile our Rust code into a shared library that can be called from Python. To do this, open the Cargo.toml file in your favorite text editor, and add the following lines to it:

[lib]
name = "rust_python_project"
crate-type = ["cdylib"]

This tells the Rust compiler that we want to create a shared library named rust_python_project, and that it should be compiled as a C-style dynamic library.

Next, create a file named src/lib.rs and add the following Rust code to it:

#[no_mangle]
pub extern fn add_one(x: u32) -> u32 {
    x + 1
}

This is a simple Rust function that takes a 32-bit unsigned integer as input, and returns the result of adding one to that number. We will use this function to demonstrate how to call Rust code from Python.

To compile the Rust code, run the following command:

cargo build --release

This will create a shared library named rust_python_project in the target/release directory. This is the library that we will call from Python.

Calling Rust Code from Python

To call the Rust code from Python, we need to use a Foreign Function Interface (FFI) library. There are several options available, but in this post we will use the cffi library. To install cffi, run the following command:

pip install cffi

Once cffi is installed, you can call the Rust code from Python using the following steps:

  1. Import the cffi library in your Python code:
import cffi
  1. Define the Rust functions and data structures that you want to call using the ffi.cdef statement:
ffi = cffi.FFI()
ffi.cdef("""uint32_t add_one(uint32_t x);""")

In this example, we are defining the add_one function from our Rust code. This tells the cffi library that we want to call a Rust function named add_one that takes a 32-bit unsigned integer as input, and returns a 32-bit unsigned integer as output.

  1. Use the ffi.dlopen function to load the compiled Rust library:
# Replace /path/to/rust/release with the actual path to the compiled Rust library
lib = ffi.dlopen("/path/to/rust/release/librust_python_project.dylib")

This will load the rust_python_project library that we created earlier using the Rust compiler.

  1. Call the Rust functions and data structures using the lib object:
# Call the add_one function from Rust
result = lib.add_one(10)
print(result) # This should print 11

This code calls the add_one function from our Rust code, passing the number 10 as the input argument. The function returns the result of adding one to that number, so the code should print the number 11 to the screen.

That’s it! You have successfully called Rust code from Python using the cffi library.

Benefits of Calling Rust Code from Python

There are several benefits to calling Rust code from Python:

Overall, calling Rust code from Python can be a powerful way to combine the best of both worlds. By using Rust for performance-critical parts of your code, and Python for the rest, you can create high-performance, reliable, and maintainable applications.

Notes

#[no_mangle]

The #[no_mangle] attribute is applied to the add_one function. This attribute tells the Rust compiler not to “mangle” the name of the function when it is compiled.

Mangling is the process of modifying the name of a function or other symbol to make it unique. This is often done to avoid conflicts with other symbols in the code, or to encode information about the symbol in its name. By default, the Rust compiler mangles the names of functions and other symbols to ensure that they are unique and do not cause conflicts.

However, in this case, we want to call the add_one function from Python. In order to do this, the name of the function must remain the same, so that Python knows which function to call. By applying the #[no_mangle] attribute to the add_one function, we are telling the Rust compiler not to mangle the name of the function, and to keep it the same as it is in the Rust code. This allows us to call the add_one function from Python without any issues.