nixide/README.md

226 lines
6.3 KiB
Markdown
Raw Normal View History

2025-12-16 01:48:56 +01:00
# Nix Bindings for Rust
2024-02-08 15:34:43 +01:00
2025-12-16 01:48:56 +01:00
Rust bindings for the Nix [C API], providing safe, idiomatic Rust interfaces to Nix's core functionality including store operations, expression evaluation, and flake management.
2024-02-08 15:34:43 +01:00
2025-12-16 01:48:56 +01:00
## Overview
2024-02-08 15:34:43 +01:00
2025-12-16 01:48:56 +01:00
This workspace provides multiple crates that wrap different layers of the Nix C API:
2025-12-16 01:48:56 +01:00
- **`nix-bindings-util`** - Utility types and helpers (settings, context, version detection, string handling)
- **`nix-bindings-store`** - Store operations (paths, derivations, store management)
- **`nix-bindings-expr`** - Expression evaluation and type extraction
- **`nix-bindings-flake`** - Flake operations
- **`nix-bindings-fetchers`** - Fetcher functionality (requires Nix ≥ 2.29)
The `*-sys` crates contain generated FFI bindings and are not intended for direct use.
2025-12-16 01:48:56 +01:00
## Features
- **Nix evaluation** - Evaluate Nix expressions and create and extract values
- **Store integration** - Interact with the Nix store, manage paths, build derivations
- **Threading** - GC registration and memory management via `Drop`
- **Lazy evaluation** - Fine-grained control over evaluation strictness
- **Version compatibility** - Conditional compilation for different Nix versions
## Quick Start
Add the crates you need to your `Cargo.toml`:
```toml
[dependencies]
nix-bindings-store = { git = "https://github.com/nixops4/nix-bindings-rust" }
nix-bindings-expr = { git = "https://github.com/nixops4/nix-bindings-rust" }
```
Basic example:
```rust
use nix_bindings_expr::eval_state::{EvalState, init, gc_register_my_thread};
use nix_bindings_store::store::Store;
use std::collections::HashMap;
fn main() -> anyhow::Result<()> {
// Initialize Nix library and register thread with GC
init()?;
let guard = gc_register_my_thread()?;
// Open a store connection and create an evaluation state
let store = Store::open(None, HashMap::new())?;
let mut eval_state = EvalState::new(store, [])?;
// Evaluate a Nix expression
let value = eval_state.eval_from_string("[1 2 3]", "<example>")?;
// Extract typed values
let elements: Vec<_> = eval_state.require_list_strict(&value)?;
for element in elements {
let num = eval_state.require_int(&element)?;
println!("Element: {}", num);
}
drop(guard);
Ok(())
}
```
## Usage Examples
### Evaluating Nix Expressions
```rust
use nix_bindings_expr::eval_state::EvalState;
// Evaluate and extract different types
let int_value = eval_state.eval_from_string("42", "<example>")?;
let num = eval_state.require_int(&int_value)?;
let str_value = eval_state.eval_from_string("\"hello\"", "<example>")?;
let text = eval_state.require_string(&str_value)?;
let attr_value = eval_state.eval_from_string("{ x = 1; y = 2; }", "<example>")?;
let attrs = eval_state.require_attrs(&attr_value)?;
```
### Working with Lists
```rust
let list_value = eval_state.eval_from_string("[1 2 3 4 5]", "<example>")?;
// Lazy: check size without evaluating elements
let size = eval_state.require_list_size(&list_value)?;
// Selective: evaluate only accessed elements
if let Some(first) = eval_state.require_list_select_idx_strict(&list_value, 0)? {
let value = eval_state.require_int(&first)?;
}
// Strict: evaluate all elements
let all_elements: Vec<_> = eval_state.require_list_strict(&list_value)?;
```
### Thread Safety
Before using `EvalState` in a thread, register with the garbage collector:
```rust
use nix_bindings_expr::eval_state::{init, gc_register_my_thread};
init()?; // Once per process
let guard = gc_register_my_thread()?; // Once per thread
// ... use EvalState ...
drop(guard); // Unregister when done
```
For more examples, see the documentation in each crate's source code.
## Nix Version Compatibility
The crates use conditional compilation to support multiple Nix versions:
- **`nix-bindings-fetchers`** requires Nix ≥ 2.29
- Some features in other crates require specific Nix versions
The build system automatically detects the Nix version and enables appropriate features.
## Integration with Nix Projects
These crates use [nix-cargo-integration] for seamless integration with Nix builds. To use them in your Nix project:
```nix
{
2025-12-16 01:48:56 +01:00
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-parts.url = "github:hercules-ci/flake-parts";
nix-cargo-integration.url = "github:90-008/nix-cargo-integration";
nix-bindings-rust.url = "github:nixops4/nix-bindings-rust";
};
outputs = inputs@{ flake-parts, ... }:
flake-parts.lib.mkFlake { inherit inputs; } {
imports = [
inputs.nix-cargo-integration.flakeModule
inputs.nix-bindings-rust.modules.flake.default
];
perSystem = { config, pkgs, ... }: {
2025-12-16 01:48:56 +01:00
# Optional: override Nix package
nix-bindings-rust.nixPackage = pkgs.nix;
nci.projects."myproject" = {
depsDrvConfig = {
imports = [ config.nix-bindings-rust.nciBuildConfig ];
};
};
};
};
}
```
2025-12-16 01:48:56 +01:00
See the [nix-cargo-integration documentation][nix-cargo-integration] for more options.
2024-02-08 15:34:43 +01:00
2025-12-16 01:48:56 +01:00
## Development
### Getting Started
2024-02-08 15:34:43 +01:00
```console
$ nix develop
```
2025-12-16 01:48:56 +01:00
### Building
```bash
# Build specific crates (release mode)
nix build .#nix-bindings-store-release
nix build .#nix-bindings-expr-release
# Build with Cargo (in dev shell)
cargo build
cargo build --release
```
### Testing
```bash
# Run tests for specific crates via Nix (recommended - includes proper store setup)
nix build .#checks.x86_64-linux.nix-bindings-store-tests
nix build .#checks.x86_64-linux.nix-bindings-expr-tests
# Run all checks (tests + clippy + formatting)
nix flake check
# Run tests with Cargo (in dev shell)
cargo test
# Run specific test
cargo test test_name
```
### Memory Testing
For FFI memory leak testing with valgrind, see [doc/hacking/test-ffi.md](doc/hacking/test-ffi.md).
### Code Formatting
```bash
treefmt
```
### IDE Setup
For VSCode, load the dev shell via Nix Env Selector extension or direnv.
## Documentation
- [API Reference](https://nixops4.github.io/nix-bindings-rust/development/)
- [Changelog](CHANGELOG.md)
2025-12-16 01:48:56 +01:00
- [Nix C API Reference][C API]
- [nix-cargo-integration][nix-cargo-integration]
- [Hacking Guide](doc/hacking/test-ffi.md)
2025-12-16 01:48:56 +01:00
## License
2025-12-16 01:48:56 +01:00
See [LICENSE](LICENSE) file in the repository.
2024-02-08 15:34:43 +01:00
[C API]: https://nix.dev/manual/nix/latest/c-api.html
2025-12-16 01:48:56 +01:00
[nix-cargo-integration]: https://github.com/90-008/nix-cargo-integration#readme