Compare commits
4 commits
7756365941
...
5930db8233
| Author | SHA1 | Date | |
|---|---|---|---|
| 5930db8233 | |||
| c9b566fc11 | |||
| 336743738e | |||
| 1e23515fc1 |
16 changed files with 291 additions and 64 deletions
32
Cargo.lock
generated
32
Cargo.lock
generated
|
|
@ -72,6 +72,22 @@ dependencies = [
|
|||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ctor"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "424e0138278faeb2b401f174ad17e715c829512d74f3d1e81eb43365c2e0590e"
|
||||
dependencies = [
|
||||
"ctor-proc-macro",
|
||||
"dtor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ctor-proc-macro"
|
||||
version = "0.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1"
|
||||
|
||||
[[package]]
|
||||
name = "doxygen-bindgen"
|
||||
version = "0.1.3"
|
||||
|
|
@ -81,6 +97,21 @@ dependencies = [
|
|||
"yap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dtor"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "404d02eeb088a82cfd873006cb713fe411306c7d182c344905e101fb1167d301"
|
||||
dependencies = [
|
||||
"dtor-proc-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dtor-proc-macro"
|
||||
version = "0.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.15.0"
|
||||
|
|
@ -190,6 +221,7 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
|||
name = "nixide"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ctor",
|
||||
"libc",
|
||||
"nixide-sys",
|
||||
"serial_test",
|
||||
|
|
|
|||
|
|
@ -19,14 +19,16 @@ targets = [ "x86_64-unknown-linux-gnu" ]
|
|||
[lib]
|
||||
path = "lib.rs"
|
||||
|
||||
# NOTE: `[features]` have a 1-1 correspondence to the
|
||||
# NOTE: shared libraries produced by the Nix C API.
|
||||
[features]
|
||||
default = ["util"]
|
||||
expr = []
|
||||
fetchers = []
|
||||
flakes = []
|
||||
store = []
|
||||
util = []
|
||||
gc = []
|
||||
default = ["nix-util-c"]
|
||||
nix-util-c = []
|
||||
nix-store-c = []
|
||||
nix-expr-c = []
|
||||
nix-fetchers-c = []
|
||||
nix-flake-c = []
|
||||
nix-main-c = []
|
||||
|
||||
[build-dependencies]
|
||||
bindgen = { default-features = false, features = [ "logging", "runtime" ], version = "0.72.1" }
|
||||
|
|
|
|||
|
|
@ -20,17 +20,26 @@ impl ParseCallbacks for DoxygenCallbacks {
|
|||
|
||||
fn main() {
|
||||
// Invalidate the built crate whenever the wrapper changes
|
||||
println!("cargo:rerun-if-changed=include/wrapper.h");
|
||||
println!("cargo:rerun-if-changed=include/nix-util.h");
|
||||
println!("cargo:rerun-if-changed=include/nix-store.h");
|
||||
println!("cargo:rerun-if-changed=include/nix-expr.h");
|
||||
println!("cargo:rerun-if-changed=include/nix-fetchers.h");
|
||||
println!("cargo:rerun-if-changed=include/nix-flake.h");
|
||||
println!("cargo:rerun-if-changed=include/nix-main.h");
|
||||
|
||||
// Use pkg-config to find nix-store include and link paths
|
||||
// This NEEDS to be included, or otherwise `nix_api_store.h` cannot
|
||||
// be found.
|
||||
let libs = [
|
||||
"nix-main-c",
|
||||
"nix-expr-c",
|
||||
"nix-store-c",
|
||||
#[cfg(feature = "nix-util-c")]
|
||||
"nix-util-c",
|
||||
#[cfg(feature = "nix-store-c")]
|
||||
"nix-store-c",
|
||||
#[cfg(feature = "nix-expr-c")]
|
||||
"nix-expr-c",
|
||||
#[cfg(feature = "nix-fetchers-c")]
|
||||
"nix-fetchers-c",
|
||||
#[cfg(feature = "nix-flake-c")]
|
||||
"nix-flake-c",
|
||||
#[cfg(feature = "nix-main-c")]
|
||||
"nix-main-c",
|
||||
];
|
||||
|
||||
let lib_args: Vec<String> = libs
|
||||
|
|
@ -50,17 +59,43 @@ fn main() {
|
|||
.flatten()
|
||||
.collect();
|
||||
|
||||
let bindings = bindgen::Builder::default()
|
||||
let mut builder = bindgen::Builder::default()
|
||||
.clang_args(lib_args)
|
||||
// The input header we would like to generate bindings for
|
||||
.header("include/wrapper.h")
|
||||
// Invalidate the built crate when an included header file changes
|
||||
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
|
||||
// Add `doxygen_bindgen` callbacks
|
||||
.parse_callbacks(Box::new(DoxygenCallbacks))
|
||||
// Format generated bindings with rustfmt
|
||||
.formatter(bindgen::Formatter::Rustfmt)
|
||||
.rustfmt_configuration_file(std::fs::canonicalize(".rustfmt.toml").ok())
|
||||
.rustfmt_configuration_file(std::fs::canonicalize(".rustfmt.toml").ok());
|
||||
|
||||
// The input headers we would like to generate bindings for
|
||||
#[cfg(feature = "nix-util-c")]
|
||||
{
|
||||
builder = builder.header("include/nix-util.h")
|
||||
}
|
||||
#[cfg(feature = "nix-store-c")]
|
||||
{
|
||||
builder = builder.header("include/nix-store.h")
|
||||
}
|
||||
#[cfg(feature = "nix-expr-c")]
|
||||
{
|
||||
builder = builder.header("include/nix-expr.h")
|
||||
}
|
||||
#[cfg(feature = "nix-fetchers-c")]
|
||||
{
|
||||
builder = builder.header("include/nix-fetchers.h")
|
||||
}
|
||||
#[cfg(feature = "nix-flake-c")]
|
||||
{
|
||||
builder = builder.header("include/nix-flake.h")
|
||||
}
|
||||
#[cfg(feature = "nix-main-c")]
|
||||
{
|
||||
builder = builder.header("include/nix-main.h")
|
||||
}
|
||||
|
||||
let bindings = builder
|
||||
// Finish the builder and generate the bindings
|
||||
.generate()
|
||||
// Unwrap the Result and panic on failure
|
||||
|
|
|
|||
10
nixide-sys/include/nix-expr.h
Normal file
10
nixide-sys/include/nix-expr.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
// Nix C API for the Nix expressions evaluator.
|
||||
#include <nix_api_expr.h>
|
||||
|
||||
// Nix C API for value manipulation.
|
||||
//
|
||||
#include <nix_api_value.h>
|
||||
|
||||
// Nix C API for external values.
|
||||
//
|
||||
#include <nix_api_external.h>
|
||||
3
nixide-sys/include/nix-fetchers.h
Normal file
3
nixide-sys/include/nix-fetchers.h
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
// Nix C API for fetcher operations.
|
||||
//
|
||||
#include <nix_api_fetchers.h>
|
||||
3
nixide-sys/include/nix-flake.h
Normal file
3
nixide-sys/include/nix-flake.h
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
// Nix C API for flake support.
|
||||
//
|
||||
#include <nix_api_flake.h>
|
||||
3
nixide-sys/include/nix-main.h
Normal file
3
nixide-sys/include/nix-main.h
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
// Nix C API for CLI support.
|
||||
//
|
||||
#include <nix_api_main.h>
|
||||
3
nixide-sys/include/nix-store.h
Normal file
3
nixide-sys/include/nix-store.h
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
// Nix C API for store operations.
|
||||
//
|
||||
#include <nix_api_store.h>
|
||||
7
nixide-sys/include/nix-util.h
Normal file
7
nixide-sys/include/nix-util.h
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
// Nix C API for utilities.
|
||||
//
|
||||
// Most notably containing functions for handling
|
||||
// the `nix_c_context` structure, which is used throughout
|
||||
// the Nix C APIs for error handling.
|
||||
//
|
||||
#include <nix_api_util.h>
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
// Pure C API for store operations
|
||||
#include <nix_api_store.h>
|
||||
|
||||
// Pure C API for error handling
|
||||
#include <nix_api_util.h>
|
||||
|
||||
// Pure C API for the Nix evaluator
|
||||
#include <nix_api_expr.h>
|
||||
|
||||
// Pure C API for external values
|
||||
#include <nix_api_external.h>
|
||||
|
||||
// Pure C API for value manipulation
|
||||
#include <nix_api_value.h>
|
||||
|
||||
// Pure C API for fetcher operations
|
||||
#include <nix_api_fetchers.h>
|
||||
|
||||
// Pure C API for flake support
|
||||
#include <nix_api_flake.h>
|
||||
|
||||
// Pure C API for main/CLI support
|
||||
#include <nix_api_main.h>
|
||||
|
|
@ -15,18 +15,16 @@ edition = "2024"
|
|||
path = "src/lib.rs"
|
||||
|
||||
[features]
|
||||
default = ["util"]
|
||||
expr = []
|
||||
fetchers = []
|
||||
flakes = []
|
||||
store = []
|
||||
util = []
|
||||
gc = []
|
||||
default = []
|
||||
store = ["nixide-sys/nix-store-c"]
|
||||
expr = ["store", "nixide-sys/nix-expr-c"]
|
||||
flake = ["store", "nixide-sys/nix-flake-c", "nixide-sys/nix-fetchers-c"]
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.183"
|
||||
stdext = "0.3.3"
|
||||
nixide-sys = { path = "../nixide-sys", version = "0.1.0" }
|
||||
ctor = "0.6.3"
|
||||
nixide-sys = { path = "../nixide-sys", version = "0.1.0", features = ["nix-util-c", "nix-main-c"]}
|
||||
|
||||
[dev-dependencies]
|
||||
serial_test = "3.4.0"
|
||||
|
|
|
|||
|
|
@ -180,11 +180,36 @@ impl ErrorContext {
|
|||
/// `nix_clear_err` only modifies the `last_err_code`, it does not
|
||||
/// clear all attributes of a `nix_c_context` struct. Hence all uses
|
||||
/// of `nix_c_context` must be careful to check the `last_err_code` regularly.
|
||||
///
|
||||
pub fn clear(&mut self) {
|
||||
unsafe {
|
||||
sys::nix_clear_err(self.as_ptr());
|
||||
}
|
||||
}
|
||||
/// This function never fails.
|
||||
/// Nixide will always guarantee `context != nullptr`.
|
||||
///
|
||||
/// # Nix C++ API Internals
|
||||
///
|
||||
/// ```cpp
|
||||
/// nix_err nix_set_err_msg(nix_c_context * context, nix_err err, const char * msg)
|
||||
/// {
|
||||
/// if (context == nullptr) {
|
||||
/// // todo last_err_code
|
||||
/// throw nix::Error("Nix C api error: %s", msg);
|
||||
/// }
|
||||
/// context->last_err_code = err;
|
||||
/// context->last_err = msg;
|
||||
/// return err;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
pub fn set_err(&self, err: NixError, msg: &str) {
|
||||
let ptr = unsafe { self.as_ptr() };
|
||||
assert!(!ptr.is_null(), "");
|
||||
|
||||
sys::nix_set_err_msg(ptr, err.into())
|
||||
}
|
||||
|
||||
/// Returns [None] if [self.code] is [sys::nix_err_NIX_OK], and [Some] otherwise.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -1,31 +1,93 @@
|
|||
// #![warn(missing_docs)]
|
||||
|
||||
// #[allow(unused_extern_crates)]
|
||||
pub extern crate libc;
|
||||
pub extern crate nixide_sys as sys;
|
||||
|
||||
pub(crate) mod errors;
|
||||
mod expr;
|
||||
// mod flake;
|
||||
mod stdext;
|
||||
mod store;
|
||||
pub(crate) mod util;
|
||||
mod verbosity;
|
||||
mod version;
|
||||
|
||||
#[cfg(feature = "expr")]
|
||||
mod expr;
|
||||
#[cfg(feature = "store")]
|
||||
mod store;
|
||||
|
||||
#[cfg(feature = "flake")]
|
||||
mod flake;
|
||||
|
||||
pub use errors::{NixError, NixideError, NixideResult};
|
||||
pub use expr::{EvalState, EvalStateBuilder, Value, ValueType};
|
||||
pub use store::{Store, StorePath};
|
||||
pub use verbosity::NixVerbosity;
|
||||
pub use version::NixVersion;
|
||||
|
||||
/// Sets the verbosity level
|
||||
#[cfg(feature = "expr")]
|
||||
pub use expr::{EvalState, EvalStateBuilder, Value, ValueType};
|
||||
#[cfg(feature = "store")]
|
||||
pub use store::{Store, StorePath};
|
||||
|
||||
use ctor::ctor;
|
||||
use util::wrappers::AsInnerPtr as _;
|
||||
|
||||
pub(crate) static mut INIT_LIBUTIL_STATUS: Option<NixideResult<()>> = None;
|
||||
#[cfg(feature = "store")]
|
||||
pub(crate) static mut INIT_LIBSTORE_STATUS: Option<NixideResult<()>> = None;
|
||||
#[cfg(feature = "expr")]
|
||||
pub(crate) static mut INIT_LIBEXPR_STATUS: Option<NixideResult<()>> = None;
|
||||
|
||||
/// # Warning
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `context` - additional error context, used as an output
|
||||
/// * `level` - verbosity level
|
||||
pub fn set_verbosity() {
|
||||
// nix_err nix_set_verbosity(nix_c_context * context, nix_verbosity level);
|
||||
// XXX: TODO: (implement Context first)
|
||||
/// > Rust's philosophy is that nothing happens before or after main and [ctor](https://github.com/mmastrac/rust-ctor)
|
||||
/// > explicitly subverts that. The code that runs in `ctor` functions
|
||||
/// > should be careful to limit itself to libc functions and code
|
||||
/// > that does not rely on Rust's stdlib services.
|
||||
/// > - Excerpt from the [github:mmastrac/rust-ctor README.md](https://github.com/mmastrac/rust-ctor?tab=readme-ov-file#warnings)
|
||||
#[ctor]
|
||||
fn init_libutil() {
|
||||
unsafe {
|
||||
INIT_LIBUTIL_STATUS = Some(util::wrap::nix_fn!(|ctx: &errors::ErrorContext| unsafe {
|
||||
sys::nix_libutil_init(ctx.as_ptr());
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
/// # TODO
|
||||
/// **Only run this if the "store" feature flag was enabled**
|
||||
///
|
||||
/// # Warning
|
||||
///
|
||||
/// > Rust's philosophy is that nothing happens before or after main and [ctor](https://github.com/mmastrac/rust-ctor)
|
||||
/// > explicitly subverts that. The code that runs in `ctor` functions
|
||||
/// > should be careful to limit itself to libc functions and code
|
||||
/// > that does not rely on Rust's stdlib services.
|
||||
/// > - Excerpt from the [github:mmastrac/rust-ctor README.md](https://github.com/mmastrac/rust-ctor?tab=readme-ov-file#warnings)
|
||||
#[ctor]
|
||||
#[cfg(feature = "store")]
|
||||
fn init_libstore() {
|
||||
// XXX: TODO: how do I support `sys::nix_libstore_init_no_load_config(context)`?
|
||||
unsafe {
|
||||
INIT_LIBSTORE_STATUS = Some(util::wrap::nix_fn!(|ctx: &errors::ErrorContext| unsafe {
|
||||
sys::nix_libutil_init(ctx.as_ptr());
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
/// # TODO
|
||||
/// **Only run this if the "expr" feature flag was enabled**
|
||||
//
|
||||
/// # Warning
|
||||
///
|
||||
/// > Rust's philosophy is that nothing happens before or after main and [ctor](https://github.com/mmastrac/rust-ctor)
|
||||
/// > explicitly subverts that. The code that runs in `ctor` functions
|
||||
/// > should be careful to limit itself to libc functions and code
|
||||
/// > that does not rely on Rust's stdlib services.
|
||||
/// > - Excerpt from the [github:mmastrac/rust-ctor README.md](https://github.com/mmastrac/rust-ctor?tab=readme-ov-file#warnings)
|
||||
#[ctor]
|
||||
#[cfg(feature = "expr")]
|
||||
fn init_libexpr() {
|
||||
unsafe {
|
||||
INIT_LIBEXPR_STATUS = Some(util::wrap::nix_fn!(|ctx: &errors::ErrorContext| unsafe {
|
||||
sys::nix_libexpr_init(ctx.as_ptr());
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
0
nixide/src/nix_settings.rs
Normal file
0
nixide/src/nix_settings.rs
Normal file
|
|
@ -5,6 +5,31 @@ use std::str::from_utf8;
|
|||
use crate::errors::new_nixide_error;
|
||||
use crate::NixideResult;
|
||||
|
||||
pub trait AsCPtr<T> {
|
||||
fn as_c_ptr(&self) -> NixideResult<*const T>;
|
||||
|
||||
fn into_c_ptr(self) -> NixideResult<*mut T>;
|
||||
}
|
||||
|
||||
impl<T> AsCPtr<c_char> for T
|
||||
where
|
||||
T: AsRef<str>,
|
||||
{
|
||||
fn as_c_ptr(&self) -> NixideResult<*const c_char> {
|
||||
match CStr::from_bytes_until_nul(self.as_ref().as_bytes()) {
|
||||
Ok(s) => Ok(s.as_ptr()),
|
||||
Err(_) => Err(new_nixide_error!(StringNulByte)),
|
||||
}
|
||||
}
|
||||
|
||||
fn into_c_ptr(self) -> NixideResult<*mut c_char> {
|
||||
match CStr::from_bytes_until_nul(self.as_ref().as_bytes()) {
|
||||
Ok(s) => Ok(s.as_ptr().cast_mut()),
|
||||
Err(_) => Err(new_nixide_error!(StringNulByte)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CCharPtrExt {
|
||||
fn to_utf8_string(self) -> NixideResult<String>;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
use crate::errors::ErrorContext;
|
||||
use crate::sys;
|
||||
use crate::util::wrappers::AsInnerPtr as _;
|
||||
use crate::util::{panic_issue, panic_issue_call_failed, wrap};
|
||||
|
||||
/// Verbosity level
|
||||
///
|
||||
|
|
@ -28,7 +31,46 @@ impl From<sys::nix_verbosity> for NixVerbosity {
|
|||
sys::nix_verbosity_NIX_LVL_CHATTY => NixVerbosity::Chatty,
|
||||
sys::nix_verbosity_NIX_LVL_DEBUG => NixVerbosity::Debug,
|
||||
sys::nix_verbosity_NIX_LVL_VOMIT => NixVerbosity::Vomit,
|
||||
_ => panic!("nixide encountered unknown `nix_verbosity` value, please submit this as an issue at https://github.com/cry128/nixide"),
|
||||
value => panic_issue!(
|
||||
"nixide encountered unknown `nix_verbosity` value ({})",
|
||||
value
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<sys::nix_verbosity> for NixVerbosity {
|
||||
fn into(self) -> sys::nix_verbosity {
|
||||
self as sys::nix_verbosity
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the verbosity level.
|
||||
///
|
||||
/// **This function should never fail!**
|
||||
/// A panic would indicate a bug in nixide itself.
|
||||
///
|
||||
/// # Nix C++ API Internals
|
||||
///
|
||||
/// ```cpp
|
||||
/// nix_err nix_set_verbosity(nix_c_context * context, nix_verbosity level)
|
||||
/// {
|
||||
/// if (context)
|
||||
/// context->last_err_code = NIX_OK;
|
||||
/// if (level > NIX_LVL_VOMIT || level < NIX_LVL_ERROR)
|
||||
/// return nix_set_err_msg(context, NIX_ERR_UNKNOWN, "Invalid verbosity level");
|
||||
/// try {
|
||||
/// nix::verbosity = static_cast<nix::Verbosity>(level);
|
||||
/// } catch (...) {
|
||||
/// return nix_context_error(context);
|
||||
/// }
|
||||
/// return NIX_OK;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
pub fn set_verbosity(level: NixVerbosity) {
|
||||
wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
|
||||
sys::nix_set_verbosity(ctx.as_ptr(), level.into());
|
||||
})
|
||||
.unwrap_or_else(|err| panic_issue_call_failed!("{}", err))
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue