Skip to main content

Crate nix_bindings

Crate nix_bindings 

Source
Expand description

High-level, safe Rust bindings for the Nix build tool.

This crate provides ergonomic and idiomatic Rust APIs for interacting with Nix using its C API.

§Quick Start

#[cfg(feature = "store")]
{
  use std::sync::Arc;

  use nix_bindings::{Context, EvalStateBuilder, Store};

  fn main() -> Result<(), Box<dyn std::error::Error>> {
    let ctx = Arc::new(Context::new()?);
    let store = Arc::new(Store::open(&ctx, None)?);
    let state = EvalStateBuilder::new(&store)?.build()?;

    let result = state.eval_from_string("1 + 2", "<eval>")?;
    println!("Result: {}", result.as_int()?);

    Ok(())
  }
}

§Thread Safety

The underlying Nix C API stores per-call error state on Context. Every C entry point that takes a nix_c_context * rewrites that buffer, so two threads sharing a Context concurrently race on it. The C++ evaluator is also not designed for concurrent mutation from multiple threads.

To make this hard to misuse, every wrapper in this crate is Send but not Sync:

TraitWhat it meansAllowed
SendMove ownership of a value to another threadyes
!SyncShare &T with another thread (incl. via Arc)no

In practice that gives you three usage patterns:

  1. Single-threaded. The common case. Build Context, Store, EvalState on one thread and stay there. Nothing extra to do.
  2. Move to a worker. Build the wrappers on the main thread, std::thread::spawn and move them in. The destination thread becomes the new sole owner.
  3. Concurrent access. Wrap the Context (or higher-level wrapper) in Arc<Mutex<_>> yourself. The bindings will not do this for you because most users do not need it, and the lock would hide the underlying single-threaded contract.

§A note on Arc<Context>

Store, EvalState, and the flake/primop/external types hold Arc<Context> so the C context lives as long as any wrapper that references it. Because Context is not Sync, Arc<Context> is not Send by Rust’s auto-traits. The wrappers nonetheless implement Send through an unsafe impl. The unsafe assertion is: when you move a wrapper across threads, no other thread retains an alias to the same Arc<Context> that it will continue to call into.

Concretely: do not clone Arc<Context>, build two stores from it, send one store to thread B, and keep using the other from thread A. That is a data race the compiler cannot catch. Either move both wrappers together, or put a Mutex in front of Context.

§Callback-scoped types

Inside a primop callback the trampoline hands you wrappers (primop::PrimOpArg, primop::PrimOpRet, primop::PrimOpValue, primop::ArgAttrs, primop::ArgList) that borrow raw pointers valid only for that one call. They are neither Send nor Sync by construction; do not stash them in a thread-local or send them off the trampoline.

§Value Formatting

Values support multiple formatting options:

#[cfg(feature = "expr")]
{
  use std::sync::Arc;

  use nix_bindings::{Context, EvalStateBuilder, Store};
  fn main() -> Result<(), Box<dyn std::error::Error>> {
    let ctx = Arc::new(Context::new()?);
    let store = Arc::new(Store::open(&ctx, None)?);
    let state = EvalStateBuilder::new(&store)?.build()?;
    let value = state.eval_from_string("\"hello world\"", "<eval>")?;

    // Display formatting (user-friendly)
    println!("{}", value); // => hello world

    // Debug formatting (with type info)
    println!("{:?}", value); // => Value::String("hello world")

    // Nix syntax formatting
    println!("{}", value.to_nix_string()?); // => "hello world"
    //
    Ok(())
  }
}

Modules§

external
External Nix values backed by Rust data.
flake
Nix flake support.
primop
Nix primitive operations (primops).

Structs§

Context
Nix context for managing library state.
Derivation
A Nix derivation loaded from its JSON representation.
EvalState
Nix evaluation state for evaluating expressions.
EvalStateBuilder
Builder for Nix evaluation state.
Store
Nix store for managing packages and derivations.
StorePath
A path in the Nix store.
Value
A Nix value.

Enums§

Error
Error types for Nix operations.
ValueType
Nix value types.
Verbosity
Verbosity level for Nix log output.

Traits§

NixValueOps
Read access to a Nix value.

Functions§

is_pure_eval
Returns true when Nix is running in pure evaluation mode (--pure-eval).
nix_version
Return the version of the Nix library being used.

Type Aliases§

Result
Result type for Nix operations.