Rust -> Python bindings
This guide explains how to add new Python bindings for Rust functions in the garaga_rs crate.
Overview
The Python bindings are implemented using PyO3, which provides a safe and ergonomic way to create Python extensions in Rust. The bindings are located in the tools/garaga_rs/src/python_bindings directory.
Adding a new binding
Create a new file in
tools/garaga_rs/src/python_bindings/for your bindingAdd the module to
mod.rsImplement your binding function
Register the function in the
garaga_rsmodule
Type Conversions
Common Type Conversions
Python Int -> Rust BigUint
let py_int: &Bound<'_, PyInt> = ...;
let biguint: BigUint = py_int.extract()?;Rust BigUint -> Python Int
let biguint: BigUint = ...;
Ok(biguint.into_pyobject(py)?.into())Python List -> Rust Vec
let py_list: &Bound<'_, PyList> = ...;
let values: Vec<BigUint> = py_list
.into_iter()
.map(|x| x.extract())
.collect::<Result<Vec<BigUint>, _>>()?;Python Bytes -> Rust Bytes
let py_bytes: &Bound<'_, PyBytes> = ...;
let bytes = py_bytes.as_bytes();Field Elements
// Python Int -> Field Element
let fe = element_from_biguint::<YourField>(&biguint);
// Field Element -> Python Int
let biguint = element_to_biguint(&fe);Error Handling
Converting Rust Errors to Python
// For custom errors
.map_err(PyErr::new::<pyo3::exceptions::PyValueError, _>)?;
// For simple error propagation
.map_err(|e| PyErr::new::<pyo3::exceptions::PyValueError, _>(e.to_string()))?Enum Conversion
let value = YourEnum::try_from(py_value)
.map_err(PyErr::new::<pyo3::exceptions::PyValueError, _>)?;Common Patterns
Function Declaration
#[pyfunction]
#[allow(clippy::too_many_arguments)] // If needed for complex functions
pub fn your_function(
py: Python,
// ... parameters ...
) -> PyResult<PyObject> {
// Implementation
}Returning Results
// For single values
Ok(result.into_pyobject(py)?.into())
// For lists
let py_list = PyList::new(py, result);
Ok(py_list?.into())
// For tuples
Ok(PyTuple::new(py, &[x, y]).into())Example Implementation
Here's a complete example showing common patterns:
use pyo3::prelude::*;
use pyo3::types::{PyInt, PyList, PyBytes};
use num_bigint::BigUint;
#[pyfunction]
pub fn example_function(
py: Python,
input_int: &Bound<'_, PyInt>,
input_list: &Bound<'_, PyList>,
input_bytes: &Bound<'_, PyBytes>,
) -> PyResult<PyObject> {
// Convert Python int to BigUint
let value: BigUint = input_int.extract()?;
// Convert Python list to Vec
let values: Vec<BigUint> = input_list
.into_iter()
.map(|x| x.extract())
.collect::<Result<Vec<BigUint>, _>>()?;
// Get bytes
let bytes = input_bytes.as_bytes();
// Do your computation
let result = process_data(&value, &values, bytes)
.map_err(PyErr::new::<pyo3::exceptions::PyValueError, _>)?;
// Return as Python list
let py_list = PyList::new(py, result);
Ok(py_list?.into())
}Registering Your Function
Add your function to the garaga_rs module in mod.rs:
#[pymodule]
fn garaga_rs(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_function(wrap_pyfunction!(your_function, m)?)?;
Ok(())
}Using the Bindings
After implementing and registering your binding, you can use it in Python like this:
from garaga import garaga_rs
# For simple integer operations
result = garaga_rs.example_function(
input_int=42,
input_list=[1, 2, 3],
input_bytes=b"some bytes"
)Testing
Add Python tests in
tests/hydra/Test both successful and error cases
Test edge cases (empty lists, zero values)
Common Pitfalls
Always use
PyResultfor error handlingRemember to propagate errors with
?Handle edge cases (e.g., zero values, maximum values)
Be careful with memory management for large data structures
Available Utilities
The following utilities are available in the codebase:
element_from_biguint: Convert BigUint to Field Elementelement_to_biguint: Convert Field Element to BigUintbiguint_to_u256: Convert BigUint to u256
Building and Testing
Build/Update the Rust extension:
maturin develop --release --features pythonRun tests:
pytest -xsBest Practices
Keep bindings simple and focused
Use appropriate error handling
Test edge cases thoroughly
Follow existing patterns in the codebase
Last updated
Was this helpful?