# Development

In Oxbow, data I/O is handled in Rust and rich features are exposed via Python. There are currently minimal bindings to R. Oxbow makes extensive use of the [`noodles`](https://github.com/zaeleus/noodles) and [`bigtools`](https://github.com/jackh726/bigtools) crates to parse genomic file formats.

The overall project is organized as a multi-project "monorepo" split into separate [Rust](https://github.com/abdenlab/oxbow/blob/main/py-oxbow), [Python](https://github.com/abdenlab/oxbow/blob/main/oxbow), and [R](https://github.com/abdenlab/oxbow/blob/main/r-oxbow) packages.


## Oxbow (Rust + Python)

### Project management

The core `oxbow` project is a pure Rust library. The code for the Python package in `py-oxbow` is a hybrid Rust-Python project. The latter requires the [`uv`](https://github.com/astral-sh/uv) package/project manager for development and relies on [PyO3](https://pyo3.rs/)'s [`maturin`](https://github.com/PyO3/maturin) as a Python build system.

Ensure you have Rust installed on your system. You can install Rust using [`rustup`](https://rustup.rs/):

```bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```

Install `uv` by following the instructions [here](https://docs.astral.sh/uv/getting-started/installation/). The Python project's dependencies are organized into [PEP 735](https://peps.python.org/pep-0735/)-style _dependency groups_ in the `pyproject.toml`. The following will create a virtual environment in `py-oxbow/.venv` with all dependency groups:

```sh
cd py-oxbow
uv sync
```

### Building the Rust crate only

The oxbow Rust crate alone can be built using the standard Rust package manager, [`cargo`](https://doc.rust-lang.org/stable/cargo/index.html). To build the library, navigate to the `oxbow` directory and run `cargo build`:

```bash
cd oxbow
cargo build  # --release (for non-debug build)
```

### Building the Rust-Python project

To (re)build and install a local development version of `oxbow` into your virtual environment:

```sh
cd py-oxbow
uvx maturin develop --uv
```

For a non-debug (and faster-running) build, add `--release`:

```sh
uvx maturin develop --uv --release
```

You can then test the build interactively:

```sh
uv run python
```

```python
>>> import oxbow as ox
>>> ...
```

or running one of the example notebooks:

```sh
uv run jupyter lab ./notebooks/bench.ipynb
```

### Linting and formatting

We use the standard Rust toolchain for linting and formatting Rust code.

[Clippy](https://doc.rust-lang.org/stable/clippy/index.html) is a Rust linter:
```bash
cargo clippy
```

The following command formats all source files of the current crate using `rustfmt`:
```bash
cargo fmt
```

We use [`ruff`](https://astral.sh/ruff) for linting and formatting Python code.

To validate the code style:
```sh
uv run ruff check
```

To format:
```sh
uv run ruff format
```

### Running Tests

To run tests on Rust code, we use `cargo`:

```bash
cargo test
```

For Python, we use [`pytest`](https://docs.pytest.org/). Tests currently need to be run from within the tests directory.

```sh
cd py-oxbow/tests
uv run pytest
```

## R interface

To build the R bindings from source, navigate to the `r-oxbow` directory and start an interactive `R` environment.
Make sure you have the [`devtools`](https://devtools.r-lib.org/) and [`rextendr`](https://github.com/extendr/rextendr) libraries installed.

Changes must be recompiled as described [here](https://extendr.github.io/rextendr/articles/package.html#compile-and-use-the-package).

```R
library(devtools)
library(rextendr)
rextendr::document()
devtools::load_all(".")
```

The Rust extension code is found in `r-oxbow/src/rust/src/lib.rs`. You can use `cargo` commands for linting, formatting, and testing the Rust code. The automatically generated `R` wrappers are found in `r-oxbow/R/extendr-wrappers.rs`. Do not edit this file manually!

In order to provide default argument values, we layer on an additional wrapper on top of what `rextendr` generates in `r-oxbow/R/api.rs`. This is the user-facing API.
