Compare commits

..

No commits in common. "cb2ac77f1edd7ecf4dac1d5de680d0674452bb37" and "f6de1d7b208d5b5396265e87c8bfce2c68c2b0f0" have entirely different histories.

25 changed files with 604 additions and 596 deletions

18
flake.lock generated
View file

@ -8,11 +8,11 @@
"rust-analyzer-src": "rust-analyzer-src" "rust-analyzer-src": "rust-analyzer-src"
}, },
"locked": { "locked": {
"lastModified": 1776025235, "lastModified": 1774682177,
"narHash": "sha256-zZIrW6G6GiFkpfFrOVjxYAVcXoKBMHv06kaUTOiqOq0=", "narHash": "sha256-OVbuJnJLlbHE28eRMudjtA6NXz/ifuXSho79gvh6GHY=",
"owner": "nix-community", "owner": "nix-community",
"repo": "fenix", "repo": "fenix",
"rev": "dfe3f197bf8f3e95d705b7323b46e3a087c88972", "rev": "e0f515387df77b9fdbaaf81e7f866f0365474c18",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -23,11 +23,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1775710090, "lastModified": 1775036866,
"narHash": "sha256-ar3rofg+awPB8QXDaFJhJ2jJhu+KqN/PRCXeyuXR76E=", "narHash": "sha256-ZojAnPuCdy657PbTq5V0Y+AHKhZAIwSIT2cb8UgAz/U=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "4c1018dae018162ec878d42fec712642d214fdfa", "rev": "6201e203d09599479a3b3450ed24fa81537ebc4e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -47,11 +47,11 @@
"rust-analyzer-src": { "rust-analyzer-src": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1775939146, "lastModified": 1774569884,
"narHash": "sha256-YI8Hkuc2PSEJNwC8Qj3/DlMt1JfRv0MqzrnH/Mh9i5s=", "narHash": "sha256-E8iWEPzg7OnE0XXXjo75CX7xFauqzJuGZ5wSO9KS8Ek=",
"owner": "rust-lang", "owner": "rust-lang",
"repo": "rust-analyzer", "repo": "rust-analyzer",
"rev": "09dc7aca674f53032f9d819f6fea01046e3d473f", "rev": "443ddcddd0c73b07b799d052f5ef3b448c2f3508",
"type": "github" "type": "github"
}, },
"original": { "original": {

201
flake.nix
View file

@ -24,6 +24,7 @@
allowUnfree = false; allowUnfree = false;
allowBroken = false; allowBroken = false;
overlays = builtins.attrValues self.overlays or {}; overlays = builtins.attrValues self.overlays or {};
# config.replaceStdenv = {pkgs}: with pkgs; llvmPackages_21.stdenv;
}; };
forAllSystems = f: forAllSystems = f:
@ -35,6 +36,9 @@
}); });
in { in {
overlays = { overlays = {
default = self: super: {
libclang = super.llvmPackages_21.libclang;
};
fenix = inputs.fenix.overlays.default; fenix = inputs.fenix.overlays.default;
}; };
@ -43,126 +47,129 @@
pkgs, pkgs,
lib, lib,
... ...
}: let }: {
nixForBindings = pkgs.nixVersions.nix_2_34; default = let
inherit (pkgs.rustc) llvmPackages; nixForBindings = pkgs.nixVersions.nix_2_34;
in { inherit (pkgs.rustc) llvmPackages;
default = pkgs.mkShell rec { in
name = "nixide"; pkgs.mkShell rec {
shell = "${pkgs.bash}/bin/bash"; name = "nixide";
strictDeps = true; shell = "${pkgs.bash}/bin/bash";
strictDeps = true;
# packages we need at runtime # packages we need at runtime
packages = with pkgs; [ packages = with pkgs; [
rustc rustc
llvmPackages.lld llvmPackages.lld
llvmPackages.lldb llvmPackages.lldb
# lldb # lldb
cargo cargo
cargo-c cargo-c
cargo-llvm-cov cargo-llvm-cov
cargo-nextest cargo-nextest
clang clang # DEBUG
clang-tools clang-tools # DEBUG
libcxx libcxx
rust-analyzer-unwrapped rust-analyzer-unwrapped
(rustfmt.override {asNightly = true;}) (rustfmt.override {asNightly = true;})
clippy clippy
taplo taplo
]; ];
# packages we need at build time # packages we need at build time
nativeBuildInputs = with pkgs; [ nativeBuildInputs = with pkgs; [
pkg-config pkg-config
glibc.dev glibc.dev
nixForBindings.dev nixForBindings.dev
rustPlatform.bindgenHook rustPlatform.bindgenHook
]; ];
# packages we link against # packages we link against
buildInputs = [ buildInputs = with pkgs; [
# pkgs.stdenv.cc stdenv.cc
nixForBindings nixForBindings
]; ];
env = { env = let
LD_LIBRARY_PATH = builtins.toString (lib.makeLibraryPath buildInputs); inherit (llvmPackages) llvm libclang;
LIBCLANG_PATH = "${llvmPackages.libclang.lib}/lib"; in {
LD_LIBRARY_PATH = builtins.toString (lib.makeLibraryPath buildInputs);
LIBCLANG_PATH = "${libclang.lib}/lib";
RUST_SRC_PATH = "${pkgs.rustPlatform.rustLibSrc}"; RUST_SRC_PATH = "${pkgs.rustPlatform.rustLibSrc}";
BINDGEN_EXTRA_CLANG_ARGS = "--sysroot=${pkgs.glibc.dev}"; BINDGEN_EXTRA_CLANG_ARGS = "--sysroot=${pkgs.glibc.dev}";
# `cargo-llvm-cov` reads these environment variables to find these binaries, # `cargo-llvm-cov` reads these environment variables to find these binaries,
# which are needed to run the tests # which are needed to run the tests
LLVM_COV = "${llvmPackages.llvm}/bin/llvm-cov"; LLVM_COV = "${llvm}/bin/llvm-cov";
LLVM_PROFDATA = "${llvmPackages.llvm}/bin/llvm-profdata"; LLVM_PROFDATA = "${llvm}/bin/llvm-profdata";
};
}; };
};
# nightly = let nightly = let
# nixForBindings = pkgs.nixVersions.nix_2_34; nixForBindings = pkgs.nixVersions.nix_2_34;
# inherit (pkgs.rustc) llvmPackages; inherit (pkgs.rustc) llvmPackages;
# in in
# pkgs.mkShell rec { pkgs.mkShell rec {
# name = "nixide"; name = "nixide";
# shell = "${pkgs.bash}/bin/bash"; shell = "${pkgs.bash}/bin/bash";
# strictDeps = true; strictDeps = true;
# # packages we need at runtime # packages we need at runtime
# packages = with pkgs; [ packages = with pkgs; [
# llvmPackages.lld llvmPackages.lld
# lldb lldb
# (pkgs.fenix.complete.withComponents [ (pkgs.fenix.complete.withComponents [
# "cargo" "cargo"
# "clippy" "clippy"
# "rust-src" "rust-src"
# "rustc" "rustc"
# "rustfmt" "rustfmt"
# ]) ])
# rust-analyzer-nightly rust-analyzer-nightly
# # cargo-c # cargo-c
# # cargo-llvm-cov # cargo-llvm-cov
# # cargo-nextest # cargo-nextest
# ]; ];
# # packages we need at build time # packages we need at build time
# nativeBuildInputs = with pkgs; [ nativeBuildInputs = with pkgs; [
# pkg-config pkg-config
# glibc.dev glibc.dev
# nixForBindings.dev nixForBindings.dev
# rustPlatform.bindgenHook rustPlatform.bindgenHook
# ]; ];
# # packages we link against # packages we link against
# buildInputs = with pkgs; [ buildInputs = with pkgs; [
# stdenv.cc stdenv.cc
# nixForBindings nixForBindings
# ]; ];
# env = let env = let
# inherit (llvmPackages) llvm libclang; inherit (llvmPackages) llvm libclang;
# in { in {
# LD_LIBRARY_PATH = builtins.toString (lib.makeLibraryPath buildInputs); LD_LIBRARY_PATH = builtins.toString (lib.makeLibraryPath buildInputs);
# LIBCLANG_PATH = "${libclang.lib}/lib"; LIBCLANG_PATH = "${libclang.lib}/lib";
# RUST_SRC_PATH = "${pkgs.rustPlatform.rustLibSrc}"; RUST_SRC_PATH = "${pkgs.rustPlatform.rustLibSrc}";
# BINDGEN_EXTRA_CLANG_ARGS = "--sysroot=${pkgs.glibc.dev}"; BINDGEN_EXTRA_CLANG_ARGS = "--sysroot=${pkgs.glibc.dev}";
# # `cargo-llvm-cov` reads these environment variables to find these binaries, # `cargo-llvm-cov` reads these environment variables to find these binaries,
# # which are needed to run the tests # which are needed to run the tests
# LLVM_COV = "${llvm}/bin/llvm-cov"; LLVM_COV = "${llvm}/bin/llvm-cov";
# LLVM_PROFDATA = "${llvm}/bin/llvm-profdata"; LLVM_PROFDATA = "${llvm}/bin/llvm-profdata";
# }; };
# }; };
} }
); );
}; };

View file

@ -128,6 +128,7 @@ fn main() {
// .cargo_debug(cfg!(debug_assertions)) // .cargo_debug(cfg!(debug_assertions))
.cpp(true) .cpp(true)
.std("c++23") // libnix compiles against `-std=c++23` .std("c++23") // libnix compiles against `-std=c++23`
.cpp_link_stdlib("c++") // libstdc++ for GNU, c++ for Clang
.opt_level((!cfg!(debug_assertions)) as u32 * 3) .opt_level((!cfg!(debug_assertions)) as u32 * 3)
.files(FEATURES.iter().map(|&feature| format!("libnixide-c/nixide_api_{feature}.cc"))) .files(FEATURES.iter().map(|&feature| format!("libnixide-c/nixide_api_{feature}.cc")))
.includes(&include_paths) .includes(&include_paths)

View file

@ -13,7 +13,7 @@ nix_err nix_register_plugin(nix_c_context * context, char * plugin)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
if (plugin == nullptr) { if (plugin == nullptr) {
// TODO: should this be `NIX_ERR_RECOVERABLE` or `NIX_ERR_UNKNOWN`? // TODO: should this be `NIX_ERR_RECOVERABLE` or `NIX_ERR_UNKNOWN`?
return nix_set_err_msg(context, NIX_ERR_UNKNOWN, "Plugin is null"); return nix_set_err_msg(context, NIX_ERR_RECOVERABLE, "Plugin is null");
} }
void * handle = dlopen("libnixmainc.so", RTLD_LAZY | RTLD_GLOBAL); void * handle = dlopen("libnixmainc.so", RTLD_LAZY | RTLD_GLOBAL);

View file

@ -21,15 +21,14 @@
// static std::optional<std::string> programName; // static std::optional<std::string> programName;
// }; // };
use std::ffi::CString;
use std::ffi::c_uint; use std::ffi::c_uint;
use std::ffi::c_void; use std::ffi::c_void;
use std::ptr::NonNull; use std::ptr::NonNull;
use super::{NixError, NixideResult}; use super::{NixError, NixideResult};
use crate::errors::ToNixideResult as _; use crate::stdext::{AsCPtr as _, CCharPtrExt as _};
use crate::stdext::CCharPtrExt as _;
use crate::sys; use crate::sys;
use crate::util::panic_issue_call_failed;
use crate::util::wrap; use crate::util::wrap;
use crate::util::wrappers::AsInnerPtr; use crate::util::wrappers::AsInnerPtr;
@ -101,7 +100,7 @@ impl Into<NixideResult<()>> for &ErrorContext {
}; };
let msg = match self.get_msg() { let msg = match self.get_msg() {
Some(msg) => msg, Some(msg) => msg,
None => String::new(), None => return Ok(()),
}; };
let err = match inner { let err = match inner {
@ -110,8 +109,13 @@ impl Into<NixideResult<()>> for &ErrorContext {
sys::NixErr::Overflow => NixError::Overflow, sys::NixErr::Overflow => NixError::Overflow,
sys::NixErr::Key => NixError::KeyNotFound(None), sys::NixErr::Key => NixError::KeyNotFound(None),
sys::NixErr::NixError => NixError::ExprEval { sys::NixErr::NixError => NixError::ExprEval {
name: self.get_nix_err_name().unwrap(), name: self
info_msg: self.get_nix_err_info_msg().unwrap_or_else(|| String::new()), .get_nix_err_name()
.unwrap_or_else(|| panic_issue_call_failed!()),
info_msg: self
.get_nix_err_info_msg()
.unwrap_or_else(|| panic_issue_call_failed!()),
}, },
// XXX: WARNING: Recoverable only exists in later version of Nix // XXX: WARNING: Recoverable only exists in later version of Nix
@ -190,11 +194,11 @@ impl ErrorContext {
/// ///
#[allow(unused)] #[allow(unused)]
pub fn set_err(&self, err: NixError, msg: &str) -> NixideResult<()> { pub fn set_err(&self, err: NixError, msg: &str) -> NixideResult<()> {
let ctx = unsafe { self.as_ptr() }; let ptr = unsafe { self.as_ptr() };
let c_msg = CString::new(msg).to_nixide_result()?; assert!(!ptr.is_null(), "");
unsafe { unsafe {
sys::nix_set_err_msg(ctx, err.err_code(), c_msg.as_ptr()); sys::nix_set_err_msg(ptr, err.err_code(), msg.as_c_ptr()?);
} }
Ok(()) Ok(())
@ -213,7 +217,7 @@ impl ErrorContext {
/// ///
/// This function **never fails**. /// This function **never fails**.
/// ///
pub fn get_err(&self) -> Option<sys::NixErr> { fn get_err(&self) -> Option<sys::NixErr> {
match unsafe { sys::nix_err_code(self.as_ptr()) } { match unsafe { sys::nix_err_code(self.as_ptr()) } {
sys::NixErr::Ok => None, sys::NixErr::Ok => None,
err => Some(err), err => Some(err),
@ -250,7 +254,7 @@ impl ErrorContext {
/// Hence we can just test whether the returned pointer is a `NULL` pointer, /// Hence we can just test whether the returned pointer is a `NULL` pointer,
/// and avoid passing in a [NixCContext] struct. /// and avoid passing in a [NixCContext] struct.
/// ///
pub fn get_msg(&self) -> Option<String> { fn get_msg(&self) -> Option<String> {
// NOTE: an Err here only occurs when `self.get_code() == Ok(())` // NOTE: an Err here only occurs when `self.get_code() == Ok(())`
let mut n: c_uint = 0; let mut n: c_uint = 0;
let result = wrap::nix_fn!(|ctx: &ErrorContext| unsafe { let result = wrap::nix_fn!(|ctx: &ErrorContext| unsafe {

View file

@ -5,16 +5,6 @@ use crate::sys;
pub type NixideResult<T> = Result<T, NixideError>; pub type NixideResult<T> = Result<T, NixideError>;
pub(crate) trait ToNixideResult<T> {
fn to_nixide_result(self) -> NixideResult<T>;
}
impl<T> ToNixideResult<T> for Result<T, std::ffi::NulError> {
fn to_nixide_result(self) -> NixideResult<T> {
Err(new_nixide_error!(StringNulByte))
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum NixideError { pub enum NixideError {
/// # Warning /// # Warning
@ -144,3 +134,16 @@ impl Display for NixideError {
} }
} }
} }
// pub trait AsErr<T> {
// fn as_err(self) -> Result<(), T>;
// }
// impl AsErr<NixideError> for Option<NixideError> {
// fn as_err(self) -> Result<(), NixideError> {
// match self {
// Some(err) => Err(err),
// None => Ok(()),
// }
// }
// }

View file

@ -4,6 +4,6 @@ mod context;
mod nix_error; mod nix_error;
pub(crate) use context::ErrorContext; pub(crate) use context::ErrorContext;
pub(crate) use error::new_nixide_error;
pub use error::{NixideError, NixideResult}; pub use error::{NixideError, NixideResult};
pub(crate) use error::{ToNixideResult, new_nixide_error};
pub use nix_error::NixError; pub use nix_error::NixError;

View file

@ -1,10 +1,11 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::ffi::CString;
use std::ptr::NonNull; use std::ptr::NonNull;
use std::rc::Rc; use std::rc::Rc;
use crate::stdext::AsCPtr as _;
use super::Value; use super::Value;
use crate::errors::{ErrorContext, ToNixideResult as _}; use crate::errors::ErrorContext;
use crate::sys; use crate::sys;
use crate::util::wrappers::AsInnerPtr; use crate::util::wrappers::AsInnerPtr;
use crate::util::{panic_issue_call_failed, wrap}; use crate::util::{panic_issue_call_failed, wrap};
@ -21,6 +22,22 @@ pub struct EvalState {
store: Rc<RefCell<Store>>, store: Rc<RefCell<Store>>,
} }
// impl Clone for EvalState {
// fn clone(&self) -> Self {
// let inner = self.inner.clone();
//
// wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
// sys::nix_gc_incref(ctx.as_ptr(), self.as_ptr() as *mut c_void);
// })
// .unwrap();
//
// Self {
// inner,
// store: self.store.clone(),
// }
// }
// }
impl AsInnerPtr<sys::EvalState> for EvalState { impl AsInnerPtr<sys::EvalState> for EvalState {
#[inline] #[inline]
unsafe fn as_ptr(&self) -> *mut sys::EvalState { unsafe fn as_ptr(&self) -> *mut sys::EvalState {
@ -70,8 +87,8 @@ impl EvalState {
/// Returns an error if evaluation fails. /// Returns an error if evaluation fails.
/// ///
pub fn interpret(&self, expr: &str, path: &str) -> NixideResult<Value> { pub fn interpret(&self, expr: &str, path: &str) -> NixideResult<Value> {
let c_expr = CString::new(expr).to_nixide_result()?; let expr = expr.as_c_ptr()?;
let c_path = CString::new(path).to_nixide_result()?; let path = path.as_c_ptr()?;
// Allocate value for result // Allocate value for result
// XXX: TODO: create a method for this (``) // XXX: TODO: create a method for this (``)
@ -82,15 +99,10 @@ impl EvalState {
// Evaluate expression // Evaluate expression
wrap::nix_fn!(|ctx: &ErrorContext| unsafe { wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_expr_eval_from_string( sys::nix_expr_eval_from_string(ctx.as_ptr(), self.as_ptr(), expr, path, value.as_ptr());
ctx.as_ptr(), value
self.as_ptr(),
c_expr.as_ptr(),
c_path.as_ptr(),
value.as_ptr(),
);
Value::from((value, self.inner_ref().clone()))
}) })
.map(|ptr| Value::from((ptr, self.inner_ref().clone())))
} }
} }

View file

@ -1,16 +1,15 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::ffi::CString;
use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
use std::ptr::{self, NonNull}; use std::ptr::{self, NonNull};
use std::rc::Rc; use std::rc::Rc;
use super::{NixThunk, NixValue, Value}; use super::{NixThunk, NixValue, Value};
use crate::errors::{ErrorContext, NixideError, ToNixideResult as _}; use crate::NixError;
use crate::stdext::CCharPtrExt; use crate::errors::{ErrorContext, NixideError};
use crate::stdext::{AsCPtr, CCharPtrExt};
use crate::sys; use crate::sys;
use crate::util::wrappers::AsInnerPtr; use crate::util::wrappers::AsInnerPtr;
use crate::util::{panic_issue_call_failed, wrap}; use crate::util::{panic_issue_call_failed, wrap};
use crate::{NixError, NixideResult};
pub struct NixAttrs { pub struct NixAttrs {
inner: NonNull<sys::NixValue>, inner: NonNull<sys::NixValue>,
@ -171,58 +170,55 @@ impl NixAttrs {
Some(name) Some(name)
} }
pub fn get<T>(&self, name: T) -> NixideResult<Option<Value>> pub fn get<T>(&self, name: T) -> Option<Value>
where where
T: AsRef<str>, T: AsRef<str>,
{ {
let c_name = CString::new(name.as_ref()).to_nixide_result()?;
let result = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe { let result = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_get_attr_byname( sys::nix_get_attr_byname(
ctx.as_ptr(), ctx.as_ptr(),
self.as_ptr(), self.as_ptr(),
self.state.borrow().as_ptr(), self.state.borrow().as_ptr(),
c_name.as_ptr(), name.as_ref()
.into_c_ptr()
.unwrap_or_else(|err| panic_issue_call_failed!("{}", err)),
) )
}); });
match result { match result {
Ok(inner) => Ok(Some(Value::from((inner, self.state.clone())))), Ok(inner) => Some(Value::from((inner, self.state.clone()))),
Err(NixideError::NixError { Err(NixideError::NixError {
err: NixError::KeyNotFound(_), err: NixError::KeyNotFound(_),
.. ..
}) => Ok(None), }) => None,
Err(err) => Err(err), Err(err) => panic_issue_call_failed!("{}", err),
} }
} }
pub fn get_lazy<T>(&self, name: T) -> NixideResult<Option<NixThunk>> pub fn get_lazy<T>(&self, name: T) -> Option<NixThunk>
where where
T: AsRef<str>, T: AsRef<str>,
{ {
let c_name = CString::new(name.as_ref()).to_nixide_result()?;
let result = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe { let result = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_get_attr_byname_lazy( sys::nix_get_attr_byname_lazy(
ctx.as_ptr(), ctx.as_ptr(),
self.as_ptr(), self.as_ptr(),
self.state.borrow().as_ptr(), self.state.borrow().as_ptr(),
c_name.as_ptr(), name.as_ref()
.into_c_ptr()
.unwrap_or_else(|err| panic_issue_call_failed!("{}", err)),
) )
}); });
match result { match result {
Ok(inner) => Ok(Some(<NixThunk as NixValue>::from( Ok(inner) => Some(<NixThunk as NixValue>::from(inner, self.state.clone())),
inner,
self.state.clone(),
))),
Err(NixideError::NixError { Err(NixideError::NixError {
err: NixError::KeyNotFound(_), err: NixError::KeyNotFound(_),
.. ..
}) => Ok(None), }) => None,
Err(err) => Err(err), Err(err) => panic_issue_call_failed!("{}", err),
} }
} }
} }

View file

@ -1,8 +1,8 @@
use std::ffi::{CString, c_char};
use std::ptr::NonNull; use std::ptr::NonNull;
use crate::NixideResult; use crate::NixideResult;
use crate::errors::{ErrorContext, ToNixideResult as _}; use crate::errors::ErrorContext;
use crate::stdext::AsCPtr as _;
use crate::sys; use crate::sys;
use crate::util::wrap; use crate::util::wrap;
use crate::util::wrappers::AsInnerPtr; use crate::util::wrappers::AsInnerPtr;
@ -11,6 +11,19 @@ pub struct FetchersSettings {
inner: NonNull<sys::NixFetchersSettings>, inner: NonNull<sys::NixFetchersSettings>,
} }
// impl Clone for FetchersSettings {
// fn clone(&self) -> Self {
// wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
// sys::nix_gc_incref(ctx.as_ptr(), self.as_ptr() as *mut c_void);
// })
// .unwrap();
//
// Self {
// inner: self.inner.clone(),
// }
// }
// }
impl Drop for FetchersSettings { impl Drop for FetchersSettings {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
@ -37,13 +50,12 @@ impl AsInnerPtr<sys::NixFetchersSettings> for FetchersSettings {
} }
impl FetchersSettings { impl FetchersSettings {
pub fn new() -> Self { pub fn new() -> NixideResult<Self> {
let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe { let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_fetchers_settings_new(ctx.as_ptr()) sys::nix_fetchers_settings_new(ctx.as_ptr())
}) })?;
.unwrap();
Self { inner } Ok(Self { inner })
} }
/// # Errors /// # Errors
@ -55,22 +67,22 @@ impl FetchersSettings {
/// It is instead **exposed by the Nixide C API extensions.** /// It is instead **exposed by the Nixide C API extensions.**
/// ///
#[allow(unused)] #[allow(unused)]
pub fn add_access_token(&self, token_name: &str, token_value: &str) -> NixideResult<()> { pub fn add_access_token(self, token_name: &str, token_value: &str) -> NixideResult<Self> {
// XXX: TODO: have a dedicated `self.access_tokens: HashMap<String, String>` instead // XXX: TODO: have a dedicated `self.access_tokens: HashMap<String, String>` instead
let c_name = CString::new(token_name).to_nixide_result()?; let name_ptr = token_name.into_c_ptr()?;
let c_value = CString::new(token_value).to_nixide_result()?; let value_ptr = token_value.into_c_ptr()?;
wrap::nix_fn!(|ctx: &ErrorContext| unsafe { wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_fetchers_settings_add_access_token( sys::nix_fetchers_settings_add_access_token(
ctx.as_ptr(), ctx.as_ptr(),
self.as_ptr(), self.as_ptr(),
c_name.as_ptr() as *mut c_char, name_ptr,
c_value.as_ptr() as *mut c_char, value_ptr,
); );
}) })
.unwrap(); .unwrap();
Ok(()) Ok(self)
} }
/// # Errors /// # Errors
@ -82,20 +94,16 @@ impl FetchersSettings {
/// It is instead **exposed by the Nixide C API extensions.** /// It is instead **exposed by the Nixide C API extensions.**
/// ///
#[allow(unused)] #[allow(unused)]
pub fn remove_access_token(&self, token_name: &str) -> NixideResult<()> { pub fn remove_access_token(self, token_name: &str) -> NixideResult<Self> {
// XXX: TODO: have a dedicated `self.access_tokens: HashMap<String, String>` instead // XXX: TODO: have a dedicated `self.access_tokens: HashMap<String, String>` instead
let c_name = CString::new(token_name).to_nixide_result()?; let name_ptr = token_name.into_c_ptr()?;
wrap::nix_fn!(|ctx: &ErrorContext| unsafe { wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_fetchers_settings_remove_access_token( sys::nix_fetchers_settings_remove_access_token(ctx.as_ptr(), self.as_ptr(), name_ptr);
ctx.as_ptr(),
self.as_ptr(),
c_name.as_ptr() as *mut c_char,
);
}) })
.unwrap(); .unwrap();
Ok(()) Ok(self)
} }
/// # Nix C API Internals /// # Nix C API Internals
@ -103,11 +111,14 @@ impl FetchersSettings {
/// This binding is **not provided by the Nix C API.** /// This binding is **not provided by the Nix C API.**
/// It is instead **exposed by the Nixide C API extensions.** /// It is instead **exposed by the Nixide C API extensions.**
/// ///
pub fn allow_dirty(&self, value: bool) { #[allow(unused)]
pub fn allow_dirty(self, value: bool) -> Self {
wrap::nix_fn!(|ctx: &ErrorContext| unsafe { wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_fetchers_settings_set_allow_dirty(ctx.as_ptr(), self.as_ptr(), value); sys::nix_fetchers_settings_set_allow_dirty(ctx.as_ptr(), self.as_ptr(), value);
}) })
.unwrap(); .unwrap();
self
} }
/// # Nix C API Internals /// # Nix C API Internals
@ -115,11 +126,14 @@ impl FetchersSettings {
/// This binding is **not provided by the Nix C API.** /// This binding is **not provided by the Nix C API.**
/// It is instead **exposed by the Nixide C API extensions.** /// It is instead **exposed by the Nixide C API extensions.**
/// ///
pub fn warn_dirty(&self, value: bool) { #[allow(unused)]
pub fn warn_dirty(self, value: bool) -> Self {
wrap::nix_fn!(|ctx: &ErrorContext| unsafe { wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_fetchers_settings_set_warn_dirty(ctx.as_ptr(), self.as_ptr(), value); sys::nix_fetchers_settings_set_warn_dirty(ctx.as_ptr(), self.as_ptr(), value);
}) })
.unwrap(); .unwrap();
self
} }
/// # Nix C API Internals /// # Nix C API Internals
@ -127,11 +141,14 @@ impl FetchersSettings {
/// This binding is **not provided by the Nix C API.** /// This binding is **not provided by the Nix C API.**
/// It is instead **exposed by the Nixide C API extensions.** /// It is instead **exposed by the Nixide C API extensions.**
/// ///
pub fn allow_dirty_locks(&self, value: bool) { #[allow(unused)]
pub fn allow_dirty_locks(self, value: bool) -> Self {
wrap::nix_fn!(|ctx: &ErrorContext| unsafe { wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_fetchers_settings_set_allow_dirty_locks(ctx.as_ptr(), self.as_ptr(), value); sys::nix_fetchers_settings_set_allow_dirty_locks(ctx.as_ptr(), self.as_ptr(), value);
}) })
.unwrap(); .unwrap();
self
} }
/// # Nix C API Internals /// # Nix C API Internals
@ -139,7 +156,8 @@ impl FetchersSettings {
/// This binding is **not provided by the Nix C API.** /// This binding is **not provided by the Nix C API.**
/// It is instead **exposed by the Nixide C API extensions.** /// It is instead **exposed by the Nixide C API extensions.**
/// ///
pub fn trust_tarballs_from_git_forges(&self, value: bool) { #[allow(unused)]
pub fn trust_tarballs_from_git_forges(self, value: bool) -> Self {
wrap::nix_fn!(|ctx: &ErrorContext| unsafe { wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_fetchers_settings_set_trust_tarballs_from_git_forges( sys::nix_fetchers_settings_set_trust_tarballs_from_git_forges(
ctx.as_ptr(), ctx.as_ptr(),
@ -148,6 +166,8 @@ impl FetchersSettings {
); );
}) })
.unwrap(); .unwrap();
self
} }
/// # Nix C API Internals /// # Nix C API Internals
@ -155,15 +175,17 @@ impl FetchersSettings {
/// This binding is **not provided by the Nix C API.** /// This binding is **not provided by the Nix C API.**
/// It is instead **exposed by the Nixide C API extensions.** /// It is instead **exposed by the Nixide C API extensions.**
/// ///
pub fn tarball_ttl(&self, ttl: u32) { #[allow(unused)]
pub fn tarball_ttl(self, ttl: u32) -> Self {
wrap::nix_fn!(|ctx: &ErrorContext| unsafe { wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_fetchers_settings_set_tarball_ttl(ctx.as_ptr(), self.as_ptr(), ttl); sys::nix_fetchers_settings_set_tarball_ttl(ctx.as_ptr(), self.as_ptr(), ttl);
}) })
.unwrap(); .unwrap();
self
} }
/// # Errors /// # Errors
///
/// Fails if the given `registry` contains a NUL byte. /// Fails if the given `registry` contains a NUL byte.
/// ///
/// # Nix C API Internals /// # Nix C API Internals
@ -171,19 +193,20 @@ impl FetchersSettings {
/// This binding is **not provided by the Nix C API.** /// This binding is **not provided by the Nix C API.**
/// It is instead **exposed by the Nixide C API extensions.** /// It is instead **exposed by the Nixide C API extensions.**
/// ///
pub fn global_flake_registry(&self, registry: &str) -> NixideResult<()> { #[allow(unused)]
let c_registry = CString::new(registry).to_nixide_result()?; pub fn global_flake_registry(self, registry: &str) -> NixideResult<Self> {
let registry_ptr = registry.into_c_ptr()?;
wrap::nix_fn!(|ctx: &ErrorContext| unsafe { wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_fetchers_settings_set_global_flake_registry( sys::nix_fetchers_settings_set_global_flake_registry(
ctx.as_ptr(), ctx.as_ptr(),
self.as_ptr(), self.as_ptr(),
c_registry.as_ptr() as *mut c_char, registry_ptr,
); );
}) })
.unwrap(); .unwrap();
Ok(()) Ok(self)
} }
} }
@ -193,6 +216,6 @@ mod tests {
#[test] #[test]
fn fetchers_settings_new() { fn fetchers_settings_new() {
let _ = FetchersSettings::new(); let _ = FetchersSettings::new().unwrap();
} }
} }

View file

@ -1,15 +1,16 @@
use std::ffi::{CString, c_char}; use std::ffi::c_char;
use std::ptr::{self, NonNull}; use std::ptr::NonNull;
use super::FlakeRef; use super::{FlakeRef, FlakeSettings};
use crate::NixideResult; use crate::NixideResult;
use crate::errors::{ErrorContext, ToNixideResult as _}; use crate::errors::ErrorContext;
use crate::stdext::AsCPtr as _;
use crate::sys; use crate::sys;
use crate::util::wrap; use crate::util::wrap;
use crate::util::wrappers::AsInnerPtr; use crate::util::wrappers::AsInnerPtr;
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum LockMode { pub enum FlakeLockMode {
/// Configures [LockedFlake::lock] to make incremental changes to the lock file as needed. Changes are written to file. /// Configures [LockedFlake::lock] to make incremental changes to the lock file as needed. Changes are written to file.
/// ///
/// This is the default mode. /// This is the default mode.
@ -27,7 +28,7 @@ pub enum LockMode {
/// Parameters that affect the locking of a flake. /// Parameters that affect the locking of a flake.
pub struct FlakeLockFlags { pub struct FlakeLockFlags {
inner: NonNull<sys::NixFlakeLockFlags>, pub(crate) inner: NonNull<sys::NixFlakeLockFlags>,
} }
// impl Clone for FlakeLockFlags { // impl Clone for FlakeLockFlags {
@ -69,38 +70,12 @@ impl AsInnerPtr<sys::NixFlakeLockFlags> for FlakeLockFlags {
} }
impl FlakeLockFlags { impl FlakeLockFlags {
pub fn new(mode: LockMode) -> Self { pub fn new(settings: &FlakeSettings) -> NixideResult<Self> {
// NOTE: `nix_flake_lock_flags_new` is a simple initialisation
// NOTE: and will only fail if out of memory (hence we can "safely" unwrap).
let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe { let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe {
// NOTE: `nix_flake_lock_flags_new` currently never uses the `settings` sys::nix_flake_lock_flags_new(ctx.as_ptr(), settings.as_ptr())
// NOTE: parameter, hence providing a null pointer is fine. })?;
sys::nix_flake_lock_flags_new(ctx.as_ptr(), ptr::null_mut())
})
.unwrap();
let self_ = FlakeLockFlags { inner }; Ok(FlakeLockFlags { inner })
wrap::nix_fn!(|ctx: &ErrorContext| {
match mode {
LockMode::WriteAsNeeded => unsafe {
sys::nix_flake_lock_flags_set_mode_write_as_needed(ctx.as_ptr(), self_.as_ptr())
},
LockMode::Virtual => unsafe {
sys::nix_flake_lock_flags_set_mode_virtual(ctx.as_ptr(), self_.as_ptr())
},
LockMode::Check => unsafe {
sys::nix_flake_lock_flags_set_mode_check(ctx.as_ptr(), self_.as_ptr())
},
};
})
.unwrap();
self_
}
pub fn default() -> Self {
Self::new(LockMode::WriteAsNeeded)
} }
/// Adds an input override to the lock file that will be produced. /// Adds an input override to the lock file that will be produced.
@ -119,13 +94,13 @@ impl FlakeLockFlags {
#[allow(unused)] #[allow(unused)]
pub fn override_input(self, input: &str, flakeref: &FlakeRef) -> NixideResult<Self> { pub fn override_input(self, input: &str, flakeref: &FlakeRef) -> NixideResult<Self> {
// XXX: TODO: should `input` be wrapped as `format!("inputs.{input}")`? // XXX: TODO: should `input` be wrapped as `format!("inputs.{input}")`?
let c_input = CString::new(input).to_nixide_result()?; let input_path = input.as_c_ptr()?;
wrap::nix_fn!(|ctx: &ErrorContext| unsafe { wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_flake_lock_flags_add_input_override( sys::nix_flake_lock_flags_add_input_override(
ctx.as_ptr(), ctx.as_ptr(),
self.as_ptr(), self.as_ptr(),
c_input.as_ptr(), input_path,
flakeref.as_ptr(), flakeref.as_ptr(),
); );
})?; })?;
@ -147,14 +122,29 @@ impl FlakeLockFlags {
#[allow(unused)] #[allow(unused)]
pub fn update_input(self, input: &str) -> NixideResult<Self> { pub fn update_input(self, input: &str) -> NixideResult<Self> {
// XXX: TODO: should `input` be wrapped as `format!("inputs.{input}")`? // XXX: TODO: should `input` be wrapped as `format!("inputs.{input}")`?
let c_input = CString::new(input).to_nixide_result()?; let input_path = input.as_c_ptr()?;
wrap::nix_fn!(|ctx: &ErrorContext| unsafe { wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_flake_lock_flags_add_input_update( sys::nix_flake_lock_flags_add_input_update(ctx.as_ptr(), self.as_ptr(), input_path);
ctx.as_ptr(), })?;
self.as_ptr(),
c_input.as_ptr(), Ok(self)
); }
#[allow(unused)]
pub fn set_mode(self, mode: FlakeLockMode) -> NixideResult<Self> {
wrap::nix_fn!(|ctx: &ErrorContext| {
match mode {
FlakeLockMode::WriteAsNeeded => unsafe {
sys::nix_flake_lock_flags_set_mode_write_as_needed(ctx.as_ptr(), self.as_ptr())
},
FlakeLockMode::Virtual => unsafe {
sys::nix_flake_lock_flags_set_mode_virtual(ctx.as_ptr(), self.as_ptr())
},
FlakeLockMode::Check => unsafe {
sys::nix_flake_lock_flags_set_mode_check(ctx.as_ptr(), self.as_ptr())
},
};
})?; })?;
Ok(self) Ok(self)
@ -290,13 +280,13 @@ impl FlakeLockFlags {
/// ///
#[allow(unused)] #[allow(unused)]
pub fn input_lock_file_path(self, path: &str) -> NixideResult<Self> { pub fn input_lock_file_path(self, path: &str) -> NixideResult<Self> {
let c_path = CString::new(path).to_nixide_result()?; let path_ptr = path.as_c_ptr()? as *mut c_char;
wrap::nix_fn!(|ctx: &ErrorContext| unsafe { wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_flake_lock_flags_set_reference_lock_file_path( sys::nix_flake_lock_flags_set_reference_lock_file_path(
ctx.as_ptr(), ctx.as_ptr(),
self.as_ptr(), self.as_ptr(),
c_path.as_ptr() as *mut c_char, path_ptr,
) )
}) })
.unwrap(); .unwrap();
@ -314,13 +304,13 @@ impl FlakeLockFlags {
/// ///
#[allow(unused)] #[allow(unused)]
pub fn output_lock_file_path(self, path: &str) -> NixideResult<Self> { pub fn output_lock_file_path(self, path: &str) -> NixideResult<Self> {
let c_path = CString::new(path).to_nixide_result()?; let path_ptr = path.as_c_ptr()? as *mut c_char;
wrap::nix_fn!(|ctx: &ErrorContext| unsafe { wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_flake_lock_flags_set_output_lock_file_path( sys::nix_flake_lock_flags_set_output_lock_file_path(
ctx.as_ptr(), ctx.as_ptr(),
self.as_ptr(), self.as_ptr(),
c_path.as_ptr() as *mut c_char, path_ptr,
) )
}) })
.unwrap(); .unwrap();

View file

@ -1,8 +1,8 @@
use std::ffi::CString;
use std::ptr::NonNull; use std::ptr::NonNull;
use crate::NixideResult; use crate::NixideResult;
use crate::errors::{ErrorContext, ToNixideResult as _}; use crate::errors::ErrorContext;
use crate::stdext::AsCPtr as _;
use crate::sys; use crate::sys;
use crate::util::wrap; use crate::util::wrap;
use crate::util::wrappers::AsInnerPtr; use crate::util::wrappers::AsInnerPtr;
@ -86,12 +86,12 @@ impl FlakeSettings {
/// ///
#[allow(unused)] #[allow(unused)]
pub fn commit_lock_file_summary(self, summary: &str) -> NixideResult<Self> { pub fn commit_lock_file_summary(self, summary: &str) -> NixideResult<Self> {
let c_summary = CString::new(summary).to_nixide_result()?; let summary_ptr = summary.into_c_ptr()?;
wrap::nix_fn!(|ctx: &ErrorContext| unsafe { wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_flake_settings_set_commit_lock_file_summary( sys::nix_flake_settings_set_commit_lock_file_summary(
ctx.as_ptr(), ctx.as_ptr(),
self.as_ptr(), self.as_ptr(),
c_summary.as_ptr().cast_mut(), summary_ptr,
) )
}) })
.unwrap(); .unwrap();

View file

@ -1,13 +1,35 @@
use std::ptr::NonNull; use std::ffi::{c_char, c_void};
use std::ptr::{NonNull, null_mut};
use super::{FetchersSettings, FlakeRefParseFlags, FlakeSettings};
use crate::NixideError;
use crate::errors::{ErrorContext, new_nixide_error};
use crate::sys; use crate::sys;
use crate::util::wrap;
use crate::util::wrappers::AsInnerPtr; use crate::util::wrappers::AsInnerPtr;
pub struct FlakeRef { pub struct FlakeRef {
inner: NonNull<sys::NixFlakeReference>, inner: NonNull<sys::NixFlakeReference>,
fragment: String, fragment: String,
fetch_settings: FetchersSettings,
flake_settings: FlakeSettings,
} }
// impl Clone for FlakeReference {
// fn clone(&self) -> Self {
// wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
// sys::nix_gc_incref(ctx.as_ptr(), self.as_ptr() as *mut c_void);
// })
// .unwrap();
//
// Self {
// inner: self.inner.clone(),
// fragment: self.fragment.clone(),
// }
// }
// }
impl Drop for FlakeRef { impl Drop for FlakeRef {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
@ -33,13 +55,45 @@ impl AsInnerPtr<sys::NixFlakeReference> for FlakeRef {
} }
} }
// XXX: TODO: is it possible to get the URI string itself? (minus the fragment part?)
impl FlakeRef { impl FlakeRef {
#[inline] /// Parse a flake reference from a string.
pub(crate) fn new(inner: NonNull<sys::NixFlakeReference>, fragment: String) -> Self { /// The string must be a valid flake reference, such as `github:owner/repo`.
Self { inner, fragment } /// It may also be suffixed with a `#` and a fragment, such as `github:owner/repo#something`,
/// in which case, the returned string will contain the fragment.
pub fn parse<S: AsRef<str>>(reference: S) -> Result<FlakeRef, NixideError> {
let fetch_settings = FetchersSettings::new()?;
let flake_settings = FlakeSettings::new()?;
let parse_flags = FlakeRefParseFlags::new(&flake_settings)?;
let mut ptr: *mut sys::NixFlakeReference = null_mut();
let fragment = wrap::nix_string_callback!(
|callback, userdata: *mut __UserData, ctx: &ErrorContext| unsafe {
sys::nix_flake_reference_and_fragment_from_string(
ctx.as_ptr(),
fetch_settings.as_ptr(),
flake_settings.as_ptr(),
parse_flags.as_ptr(),
reference.as_ref().as_ptr() as *const c_char,
reference.as_ref().len(),
&mut ptr,
Some(callback),
userdata as *mut c_void,
)
}
)?;
match NonNull::new(ptr) {
Some(inner) => Ok(FlakeRef {
inner,
fragment,
fetch_settings,
flake_settings,
}),
None => Err(new_nixide_error!(NullPtr)),
}
} }
// XXX: TODO: is it possible to get the URI string itself? (minus the fragment part?)
/// Get a shared reference to the URI fragment part. /// Get a shared reference to the URI fragment part.
/// ///
#[inline] #[inline]

View file

@ -1,104 +0,0 @@
use std::ffi::{CString, c_void};
use std::path::Path;
use std::ptr::{self, NonNull, null_mut};
use super::{FetchersSettings, FlakeRef, FlakeRefParseFlags};
use crate::errors::{ErrorContext, NixideResult, ToNixideResult as _, new_nixide_error};
use crate::sys;
use crate::util::wrap;
use crate::util::wrappers::AsInnerPtr;
pub struct FlakeRefBuilder {
reference: String,
fetch_settings: FetchersSettings,
parse_flags: FlakeRefParseFlags,
}
impl FlakeRefBuilder {
/// Parse a flake reference from a string.
///
/// The string must be a valid flake reference, such as `github:owner/repo`.
///
/// It may also be suffixed with a `#` and a fragment, such as `github:owner/repo#something`,
/// in which case, the returned string will contain the fragment.
///
pub fn new<S: AsRef<str>>(reference: S) -> Self {
Self {
reference: reference.as_ref().to_string(),
fetch_settings: FetchersSettings::new(),
parse_flags: FlakeRefParseFlags::new(),
}
}
pub fn build(&self) -> NixideResult<FlakeRef> {
let c_reference = CString::new(self.reference.as_str()).to_nixide_result()?;
let mut ptr: *mut sys::NixFlakeReference = null_mut();
let fragment = wrap::nix_string_callback!(
|callback, userdata: *mut __UserData, ctx: &ErrorContext| unsafe {
// NOTE: `nix_flake_reference_and_fragment_from_string` currently
// NOTE: never uses the `flake_settings` parameter, hence providing
// NOTE: a null pointer instead is fine.
sys::nix_flake_reference_and_fragment_from_string(
ctx.as_ptr(),
self.fetch_settings.as_ptr(),
ptr::null_mut(),
self.parse_flags.as_ptr(),
c_reference.as_ptr(),
self.reference.len(),
&mut ptr,
Some(callback),
userdata as *mut c_void,
)
}
)?;
match NonNull::new(ptr) {
Some(inner) => Ok(FlakeRef::new(inner, fragment)),
None => Err(new_nixide_error!(NullPtr)),
}
}
pub fn base_directory<P: AsRef<Path>>(mut self, path: P) -> NixideResult<Self> {
self.parse_flags
.base_directory(&path.as_ref().to_string_lossy())?;
Ok(self)
}
pub fn global_flake_registry(self, registry: &str) -> NixideResult<Self> {
self.fetch_settings.global_flake_registry(registry)?;
Ok(self)
}
pub fn allow_dirty(self, value: bool) -> Self {
self.fetch_settings.allow_dirty(value);
self
}
pub fn warn_dirty(self, value: bool) -> Self {
self.fetch_settings.warn_dirty(value);
self
}
pub fn allow_dirty_locks(self, value: bool) -> Self {
self.fetch_settings.allow_dirty_locks(value);
self
}
pub fn trust_tarballs_from_git_forges(self, value: bool) -> Self {
self.fetch_settings.trust_tarballs_from_git_forges(value);
self
}
pub fn tarball_ttl(self, ttl: u32) -> Self {
self.fetch_settings.tarball_ttl(ttl);
self
}
}

View file

@ -1,29 +1,36 @@
use std::ffi::CString; use std::ffi::c_char;
use std::ptr::{self, NonNull}; use std::ptr::NonNull;
use crate::errors::{ErrorContext, ToNixideResult as _}; use super::FlakeSettings;
use crate::NixideResult;
use crate::errors::ErrorContext;
use crate::sys;
use crate::util::wrap; use crate::util::wrap;
use crate::util::wrappers::AsInnerPtr; use crate::util::wrappers::AsInnerPtr;
use crate::{NixideResult, sys};
/// Parameters for parsing a flake reference. /// Parameters for parsing a flake reference.
///
/// # Nix C API Internals
///
/// Currently the Nix C API only uses this for storing
/// a base directory... Kinda overkill no? ;w;
///
#[derive(Debug)] #[derive(Debug)]
// pub(super) struct FlakeRefParseFlags {
pub struct FlakeRefParseFlags { pub struct FlakeRefParseFlags {
// DEBUG (go back to pub(super) soon)
inner: NonNull<sys::NixFlakeReferenceParseFlags>, inner: NonNull<sys::NixFlakeReferenceParseFlags>,
} }
// impl Clone for FlakeReferenceParseFlags {
// fn clone(&self) -> Self {
// wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
// sys::nix_gc_incref(ctx.as_ptr(), self.as_ptr() as *mut c_void);
// })
// .unwrap();
//
// Self {
// inner: self.inner.clone(),
// }
// }
// }
impl Drop for FlakeRefParseFlags { impl Drop for FlakeRefParseFlags {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
sys::nix_flake_reference_parse_flags_free(self.as_ptr()); sys::nix_flake_reference_parse_flags_free(self.inner.as_ptr());
} }
} }
} }
@ -46,40 +53,24 @@ impl AsInnerPtr<sys::NixFlakeReferenceParseFlags> for FlakeRefParseFlags {
} }
impl FlakeRefParseFlags { impl FlakeRefParseFlags {
pub fn new() -> Self { pub fn new(settings: &FlakeSettings) -> NixideResult<Self> {
// NOTE: `nix_flake_reference_parse_flags_new` is a simple initialisation
// NOTE: and will only fail if out of memory (hence we can "safely" unwrap).
let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe { let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe {
// NOTE: `nix_flake_reference_parse_flags_new` currently never uses the `settings` sys::nix_flake_reference_parse_flags_new(ctx.as_ptr(), settings.as_ptr())
// NOTE: parameter, hence providing a null pointer is fine. })?;
sys::nix_flake_reference_parse_flags_new(ctx.as_ptr(), ptr::null_mut())
})
.unwrap();
Self { inner } Ok(Self { inner })
} }
/// Sets the [base directory](https://nix.dev/manual/nix/latest/glossary#gloss-base-directory) /// Sets the [base directory](https://nix.dev/manual/nix/latest/glossary#gloss-base-directory)
/// for resolving local flake references. /// for resolving local flake references.
/// pub fn set_base_directory(&mut self, base_directory: &str) -> NixideResult<()> {
/// # Nix C API Internals
///
/// If `set_base_directory` is never called, the base directory defaults
/// to the current working directory (see `libutil/filesystem.cc:absPath`).
///
pub fn base_directory(&mut self, base_directory: &str) -> NixideResult<()> {
let c_base_directory = CString::new(base_directory).to_nixide_result()?;
wrap::nix_fn!(|ctx: &ErrorContext| unsafe { wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_flake_reference_parse_flags_set_base_directory( sys::nix_flake_reference_parse_flags_set_base_directory(
ctx.as_ptr(), ctx.as_ptr(),
self.as_ptr(), self.as_ptr(),
c_base_directory.as_ptr(), base_directory.as_ptr() as *const c_char,
base_directory.len(), base_directory.len(),
); );
}) })
.unwrap();
Ok(())
} }
} }

View file

@ -1,8 +1,10 @@
// XXX: TODO: find a way to read directly from FlakeSettings and FetchersSettings (the C++ classes)
use std::cell::RefCell; use std::cell::RefCell;
use std::ptr::{self, NonNull}; use std::ptr::NonNull;
use std::rc::Rc; use std::rc::Rc;
use super::{FlakeLockFlags, FlakeRef, FlakeRefBuilder, FlakeSettings}; use super::{FetchersSettings, FlakeLockFlags, FlakeLockMode, FlakeRef, FlakeSettings};
use crate::errors::ErrorContext; use crate::errors::ErrorContext;
use crate::sys; use crate::sys;
use crate::util::wrap; use crate::util::wrap;
@ -15,6 +17,7 @@ pub struct LockedFlake {
flakeref: FlakeRef, flakeref: FlakeRef,
state: Rc<RefCell<NonNull<sys::EvalState>>>, state: Rc<RefCell<NonNull<sys::EvalState>>>,
lock_flags: FlakeLockFlags, lock_flags: FlakeLockFlags,
fetch_settings: FetchersSettings,
flake_settings: FlakeSettings, flake_settings: FlakeSettings,
} }
@ -45,19 +48,19 @@ impl AsInnerPtr<sys::NixLockedFlake> for LockedFlake {
impl LockedFlake { impl LockedFlake {
pub fn lock( pub fn lock(
lock_flags: FlakeLockFlags, mode: FlakeLockMode,
flakeref: FlakeRef, flakeref: FlakeRef,
state: &EvalState, state: &EvalState,
) -> NixideResult<LockedFlake> { ) -> NixideResult<LockedFlake> {
let state_inner = state.inner_ref(); let state_inner = state.inner_ref();
let fetch_settings = FetchersSettings::new()?;
let flake_settings = FlakeSettings::new()?; let flake_settings = FlakeSettings::new()?;
let lock_flags = FlakeLockFlags::new(&flake_settings)?.set_mode(mode)?;
let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe { let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe {
// NOTE: `nix_flake_lock` currently never uses the `fetchSettings`
// NOTE: parameter, hence providing a null pointer instead is fine.
sys::nix_flake_lock( sys::nix_flake_lock(
ctx.as_ptr(), ctx.as_ptr(),
ptr::null_mut(), fetch_settings.as_ptr(),
flake_settings.as_ptr(), flake_settings.as_ptr(),
state_inner.borrow().as_ptr(), state_inner.borrow().as_ptr(),
lock_flags.as_ptr(), lock_flags.as_ptr(),
@ -70,6 +73,7 @@ impl LockedFlake {
flakeref, flakeref,
state: state_inner.clone(), state: state_inner.clone(),
lock_flags, lock_flags,
fetch_settings,
flake_settings, flake_settings,
}) })
} }
@ -94,8 +98,8 @@ mod tests {
use std::fs; use std::fs;
use std::sync::Once; use std::sync::Once;
use super::{FlakeLockFlags, FlakeRefBuilder, FlakeSettings, LockedFlake}; use super::{FetchersSettings, FlakeLockFlags, FlakeRef, FlakeSettings, LockedFlake};
use crate::flake::LockMode; use crate::flake::{FlakeLockMode, FlakeRefParseFlags};
use crate::{EvalStateBuilder, Store, Value, set_global_setting}; use crate::{EvalStateBuilder, Store, Value, set_global_setting};
static INIT: Once = Once::new(); static INIT: Once = Once::new();
@ -157,16 +161,12 @@ mod tests {
.build() .build()
.unwrap(); .unwrap();
// let flakeref = FlakeRefBuilder::new(format!("path:{}#subthing", tmp_dir.path().display())) // DEBUG let flakeref =
let flakeref = FlakeRefBuilder::new(format!("{}#subthing", tmp_dir.path().display())) FlakeRef::parse(&format!("path:{}#subthing", tmp_dir.path().display())).unwrap();
.build()
.unwrap();
assert_eq!(flakeref.fragment(), "subthing"); assert_eq!(flakeref.fragment(), "subthing");
let flake_lock_flags = FlakeLockFlags::new(LockMode::WriteAsNeeded); let outputs = LockedFlake::lock(FlakeLockMode::WriteAsNeeded, flakeref, &eval_state)
let outputs = LockedFlake::lock(flake_lock_flags, flakeref, &eval_state)
.unwrap() .unwrap()
.outputs() .outputs()
.unwrap(); .unwrap();
@ -175,203 +175,215 @@ mod tests {
if let Value::Attrs(outputs) = outputs { if let Value::Attrs(outputs) = outputs {
let value = outputs.get("hello").unwrap(); let value = outputs.get("hello").unwrap();
assert!(matches!(value, Some(Value::String(_)))); assert!(matches!(value, Value::String(_)));
if let Some(Value::String(value)) = value { if let Value::String(value) = value {
assert_eq!(value.as_string(), "world"); assert_eq!(value.as_string(), "world");
} }
} }
} }
// #[test] # DEBUG (too lazy to keep fixing this function...) #[test]
// fn flake_lock_load_flake_with_flags() { fn flake_lock_load_flake_with_flags() {
// init(); init();
// let store_ref = Store::default().unwrap(); let store_ref = Store::default().unwrap();
// let flake_settings = FlakeSettings::new().unwrap(); let fetchers_settings = FetchersSettings::new().unwrap();
// let eval_state = EvalStateBuilder::new(store_ref.clone()) let flake_settings = FlakeSettings::new().unwrap();
// .unwrap() let eval_state = EvalStateBuilder::new(store_ref.clone())
// .set_flake_settings(&flake_settings) .unwrap()
// .unwrap() .set_flake_settings(&flake_settings)
// .build() .unwrap()
// .unwrap(); .build()
.unwrap();
// let tmp_dir = tempfile::tempdir().unwrap(); let tmp_dir = tempfile::tempdir().unwrap();
// let flake_dir_a = tmp_dir.path().join("a"); let flake_dir_a = tmp_dir.path().join("a");
// let flake_dir_b = tmp_dir.path().join("b"); let flake_dir_b = tmp_dir.path().join("b");
// let flake_dir_c = tmp_dir.path().join("c"); let flake_dir_c = tmp_dir.path().join("c");
// std::fs::create_dir_all(&flake_dir_a).unwrap(); std::fs::create_dir_all(&flake_dir_a).unwrap();
// std::fs::create_dir_all(&flake_dir_b).unwrap(); std::fs::create_dir_all(&flake_dir_b).unwrap();
// std::fs::create_dir_all(&flake_dir_c).unwrap(); std::fs::create_dir_all(&flake_dir_c).unwrap();
// let flake_dir_a_str = flake_dir_a.to_str().unwrap(); let flake_dir_a_str = flake_dir_a.to_str().unwrap();
// let flake_dir_c_str = flake_dir_c.to_str().unwrap(); let flake_dir_c_str = flake_dir_c.to_str().unwrap();
// assert!(!flake_dir_a_str.is_empty()); assert!(!flake_dir_a_str.is_empty());
// assert!(!flake_dir_c_str.is_empty()); assert!(!flake_dir_c_str.is_empty());
// // a // a
// std::fs::write( std::fs::write(
// tmp_dir.path().join("a/flake.nix"), tmp_dir.path().join("a/flake.nix"),
// r#" r#"
// { {
// inputs.b.url = "@flake_dir_b@"; inputs.b.url = "@flake_dir_b@";
// outputs = { b, ... }: { outputs = { b, ... }: {
// hello = b.hello; hello = b.hello;
// }; };
// } }
// "# "#
// .replace("@flake_dir_b@", flake_dir_b.to_str().unwrap()), .replace("@flake_dir_b@", flake_dir_b.to_str().unwrap()),
// ) )
// .unwrap(); .unwrap();
// // b // b
// std::fs::write( std::fs::write(
// tmp_dir.path().join("b/flake.nix"), tmp_dir.path().join("b/flake.nix"),
// r#" r#"
// { {
// outputs = { ... }: { outputs = { ... }: {
// hello = "ALICE"; hello = "ALICE";
// }; };
// } }
// "#, "#,
// ) )
// .unwrap(); .unwrap();
// // c // c
// std::fs::write( std::fs::write(
// tmp_dir.path().join("c/flake.nix"), tmp_dir.path().join("c/flake.nix"),
// r#" r#"
// { {
// outputs = { ... }: { outputs = { ... }: {
// hello = "Claire"; hello = "Claire";
// }; };
// } }
// "#, "#,
// ) )
// .unwrap(); .unwrap();
// let flakeref_a = FlakeRefBuilder::new(format!("path:{}", &flake_dir_a_str)) let mut flake_lock_flags = FlakeLockFlags::new(&flake_settings).unwrap();
// .build()
// .unwrap();
// assert_eq!(flakeref_a.fragment(), ""); let mut flake_reference_parse_flags = FlakeRefParseFlags::new(&flake_settings).unwrap();
// // Step 1: Do not update (check), fails flake_reference_parse_flags
// let mut flake_lock_flags = FlakeLockFlags::new(LockMode::Check); .set_base_directory(tmp_dir.path().to_str().unwrap())
.unwrap();
// let locked_flake = LockedFlake::lock(flake_lock_flags, flakeref_a, &eval_state); let flakeref_a = FlakeRef::parse(&format!("path:{}", &flake_dir_a_str)).unwrap();
// // Has not been locked and would need to write a lock file.
// assert!(locked_flake.is_err());
// let saved_err = match locked_flake {
// Ok(_) => panic!("Expected error, but got Ok"),
// Err(e) => e,
// };
// // Step 2: Update but do not write, succeeds assert_eq!(flakeref_a.fragment(), "");
// let flake_lock_flags = FlakeLockFlags::new(LockMode::Virtual);
// let locked_flake = LockedFlake::lock(flake_lock_flags, flakeref_a, &eval_state).unwrap(); // Step 1: Do not update (check), fails
flake_lock_flags.set_mode(FlakeLockMode::Check).unwrap();
// let outputs = locked_flake.outputs().unwrap(); let locked_flake = LockedFlake::lock(FlakeLockMode::Check, flakeref_a, &eval_state);
// Has not been locked and would need to write a lock file.
assert!(locked_flake.is_err());
let saved_err = match locked_flake {
Ok(_) => panic!("Expected error, but got Ok"),
Err(e) => e,
};
// assert!(matches!(outputs, Value::Attrs(_))); // Step 2: Update but do not write, succeeds
// if let Value::Attrs(outputs) = outputs { flake_lock_flags.set_mode(FlakeLockMode::Virtual).unwrap();
// let value = outputs.get("hello").unwrap();
// assert!(matches!(value, Value::String(_))); let locked_flake = LockedFlake::lock(flake_lock_flags, flakeref_a, &eval_state).unwrap();
// if let Value::String(value) = value {
// assert_eq!(value.as_string(), "ALICE");
// }
// }
// // Step 3: The lock was not written, so Step 1 would fail again let outputs = locked_flake.outputs().unwrap();
// let flake_lock_flags = FlakeLockFlags::new(LockMode::Check);
// let locked_flake = LockedFlake::lock(flake_lock_flags, flakeref_a, &eval_state); assert!(matches!(outputs, Value::Attrs(_)));
// // Has not been locked and would need to write a lock file. if let Value::Attrs(outputs) = outputs {
// match locked_flake { let value = outputs.get("hello").unwrap();
// Ok(_) => panic!("Expected error, but got Ok"),
// Err(e) => {
// assert_eq!(e.to_string(), saved_err.to_string());
// },
// };
// // Step 4: Update and write, succeeds assert!(matches!(value, Value::String(_)));
// let flake_lock_flags = FlakeLockFlags::new(LockMode::WriteAsNeeded); if let Value::String(value) = value {
assert_eq!(value.as_string(), "ALICE");
}
}
// let locked_flake = LockedFlake::lock(flake_lock_flags, flakeref_a, &eval_state).unwrap(); // Step 3: The lock was not written, so Step 1 would fail again
flake_lock_flags.set_mode(FlakeLockMode::Check).unwrap();
// let outputs = locked_flake.outputs().unwrap(); let locked_flake = LockedFlake::lock(flake_lock_flags, flakeref_a, &eval_state);
// Has not been locked and would need to write a lock file.
match locked_flake {
Ok(_) => panic!("Expected error, but got Ok"),
Err(e) => {
assert_eq!(e.to_string(), saved_err.to_string());
},
};
// assert!(matches!(outputs, Value::Attrs(_))); // Step 4: Update and write, succeeds
// if let Value::Attrs(outputs) = outputs { flake_lock_flags
// let value = outputs.get("hello").unwrap(); .set_mode(FlakeLockMode::WriteAsNeeded)
.unwrap();
// assert!(matches!(value, Value::String(_))); let locked_flake = LockedFlake::lock(flake_lock_flags, flakeref_a, &eval_state).unwrap();
// if let Value::String(value) = value {
// assert_eq!(value.as_string(), "ALICE");
// }
// }
// // Step 5: Lock was written, so Step 1 succeeds let outputs = locked_flake.outputs().unwrap();
// let flake_lock_flags = FlakeLockFlags::new(LockMode::Check);
// let locked_flake = LockedFlake::lock(flake_lock_flags, flakeref_a, &eval_state).unwrap(); assert!(matches!(outputs, Value::Attrs(_)));
if let Value::Attrs(outputs) = outputs {
let value = outputs.get("hello").unwrap();
// let outputs = locked_flake.outputs().unwrap(); assert!(matches!(value, Value::String(_)));
if let Value::String(value) = value {
assert_eq!(value.as_string(), "ALICE");
}
}
// assert!(matches!(outputs, Value::Attrs(_))); // Step 5: Lock was written, so Step 1 succeeds
// if let Value::Attrs(outputs) = outputs { flake_lock_flags.set_mode(FlakeLockMode::Check).unwrap();
// let value = outputs.get("hello").unwrap();
// assert!(matches!(value, Value::String(_))); let locked_flake = LockedFlake::lock(flake_lock_flags, flakeref_a, &eval_state).unwrap();
// if let Value::String(value) = value {
// assert_eq!(value.as_string(), "ALICE");
// }
// }
// // Step 6: Lock with override, do not write let outputs = locked_flake.outputs().unwrap();
// // This shouldn't matter; write_as_needed will be overridden assert!(matches!(outputs, Value::Attrs(_)));
// let flake_lock_flags = FlakeLockFlags::new(LockMode::WriteAsNeeded); if let Value::Attrs(outputs) = outputs {
let value = outputs.get("hello").unwrap();
// let flakeref_c = FlakeRefBuilder::new(format!("path:{}", &flake_dir_c_str)) assert!(matches!(value, Value::String(_)));
// .build() if let Value::String(value) = value {
// .unwrap(); assert_eq!(value.as_string(), "ALICE");
// assert_eq!(flakeref_c.fragment(), ""); }
}
// flake_lock_flags.override_input("b", &flakeref_c).unwrap(); // Step 6: Lock with override, do not write
// let locked_flake = LockedFlake::lock(flake_lock_flags, flakeref_a, &eval_state).unwrap(); // This shouldn't matter; write_as_needed will be overridden
flake_lock_flags
.set_mode(FlakeLockMode::WriteAsNeeded)
.unwrap();
// let outputs = locked_flake.outputs().unwrap(); let flakeref_c = FlakeRef::parse(&format!("path:{}", &flake_dir_c_str)).unwrap();
assert_eq!(flakeref_c.fragment(), "");
// assert!(matches!(outputs, Value::Attrs(_))); flake_lock_flags.override_input("b", &flakeref_c).unwrap();
// if let Value::Attrs(outputs) = outputs {
// let value = outputs.get("hello").unwrap();
// assert!(matches!(value, Value::String(_))); let locked_flake = LockedFlake::lock(flake_lock_flags, flakeref_a, &eval_state).unwrap();
// if let Value::String(value) = value {
// assert_eq!(value.as_string(), "Claire");
// }
// }
// // Step 7: Override was not written; lock still points to b let outputs = locked_flake.outputs().unwrap();
// let flake_lock_flags = FlakeLockFlags::new(LockMode::Check);
// let locked_flake = LockedFlake::lock(flake_lock_flags, flakeref_a, &eval_state).unwrap(); assert!(matches!(outputs, Value::Attrs(_)));
if let Value::Attrs(outputs) = outputs {
let value = outputs.get("hello").unwrap();
// let outputs = locked_flake.outputs().unwrap(); assert!(matches!(value, Value::String(_)));
if let Value::String(value) = value {
assert_eq!(value.as_string(), "Claire");
}
}
// assert!(matches!(outputs, Value::Attrs(_))); // Can't delete overrides, so trash it
// if let Value::Attrs(outputs) = outputs { let mut flake_lock_flags = FlakeLockFlags::new(&flake_settings).unwrap();
// let value = outputs.get("hello").unwrap();
// assert!(matches!(value, Value::String(_))); // Step 7: Override was not written; lock still points to b
// if let Value::String(value) = value { flake_lock_flags.set_mode(FlakeLockMode::Check).unwrap();
// assert_eq!(value.as_string(), "ALICE");
// } let locked_flake = LockedFlake::lock(flake_lock_flags, flakeref_a, &eval_state).unwrap();
// }
// } let outputs = locked_flake.outputs().unwrap();
assert!(matches!(outputs, Value::Attrs(_)));
if let Value::Attrs(outputs) = outputs {
let value = outputs.get("hello").unwrap();
assert!(matches!(value, Value::String(_)));
if let Value::String(value) = value {
assert_eq!(value.as_string(), "ALICE");
}
}
}
} }

View file

@ -2,14 +2,12 @@ mod fetchers_settings;
mod flake_lock_flags; mod flake_lock_flags;
mod flake_settings; mod flake_settings;
mod flakeref; mod flakeref;
mod flakeref_builder;
mod flakeref_parse_flags; mod flakeref_parse_flags;
mod locked_flake; mod locked_flake;
pub use fetchers_settings::FetchersSettings; use fetchers_settings::FetchersSettings;
pub use flake_lock_flags::{FlakeLockFlags, LockMode}; use flake_lock_flags::{FlakeLockFlags, FlakeLockMode};
pub use flake_settings::FlakeSettings; pub use flake_settings::FlakeSettings;
pub use flakeref::FlakeRef; use flakeref::FlakeRef;
pub use flakeref_builder::FlakeRefBuilder; use flakeref_parse_flags::FlakeRefParseFlags;
pub use flakeref_parse_flags::FlakeRefParseFlags;
pub use locked_flake::LockedFlake; pub use locked_flake::LockedFlake;

View file

@ -29,6 +29,6 @@ pub use version::NixVersion;
#[cfg(feature = "exprs")] #[cfg(feature = "exprs")]
pub use expr::{EvalState, EvalStateBuilder, Value}; pub use expr::{EvalState, EvalStateBuilder, Value};
#[cfg(feature = "flakes")] #[cfg(feature = "flakes")]
pub use flake::{FlakeRef, FlakeRefBuilder, FlakeSettings, LockedFlake}; pub use flake::{FlakeSettings, LockedFlake};
#[cfg(feature = "store")] #[cfg(feature = "store")]
pub use store::{Store, StorePath}; pub use store::{Store, StorePath};

View file

@ -1,6 +1,5 @@
use std::ffi::CString; use crate::errors::ErrorContext;
use crate::stdext::AsCPtr as _;
use crate::errors::{ErrorContext, ToNixideResult as _};
use crate::sys; use crate::sys;
use crate::util::wrap; use crate::util::wrap;
use crate::util::wrappers::AsInnerPtr as _; use crate::util::wrappers::AsInnerPtr as _;
@ -70,10 +69,8 @@ impl ToString for LogFormat {
/// modified without nixide updating to account for this. /// modified without nixide updating to account for this.
/// ///
pub fn set_log_format(format: LogFormat) { pub fn set_log_format(format: LogFormat) {
let c_format = CString::new(format.to_string()).to_nixide_result().unwrap();
wrap::nix_fn!(|ctx: &ErrorContext| unsafe { wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_set_log_format(ctx.as_ptr(), c_format.as_ptr()); sys::nix_set_log_format(ctx.as_ptr(), format.to_string().as_c_ptr().unwrap());
}) })
.unwrap() .unwrap()
} }

View file

@ -1,26 +1,21 @@
use std::ffi::{CString, c_void}; use std::ffi::c_void;
use crate::NixideResult; use crate::NixideResult;
use crate::errors::{ErrorContext, ToNixideResult as _}; use crate::errors::ErrorContext;
use crate::stdext::AsCPtr as _;
use crate::util::wrap; use crate::util::wrap;
use crate::util::wrappers::AsInnerPtr as _; use crate::util::wrappers::AsInnerPtr as _;
// DEBUG: should this really be unsafe?
/// # Note /// # Note
/// This function is intentionally marked unsafe to discourage its use. /// This function is intentionally marked unsafe to discourage its use.
/// Please prefer [nixide::FlakeSettings] and [nixide::FetchersSettings]. /// Please prefer [nixide::FlakeSettings] and [nixide::FetchersSettings].
/// ///
pub unsafe fn get_global_setting(key: &str) -> NixideResult<String> { pub unsafe fn get_global_setting<S: AsRef<str>>(key: S) -> NixideResult<String> {
let c_key = CString::new(key).to_nixide_result()?; let key = key.as_c_ptr()?;
wrap::nix_string_callback!( wrap::nix_string_callback!(
|callback, userdata: *mut __UserData, ctx: &ErrorContext| unsafe { |callback, userdata: *mut __UserData, ctx: &ErrorContext| unsafe {
sys::nix_setting_get( sys::nix_setting_get(ctx.as_ptr(), key, Some(callback), userdata as *mut c_void);
ctx.as_ptr(),
c_key.as_ptr(),
Some(callback),
userdata as *mut c_void,
);
} }
) )
} }
@ -29,11 +24,14 @@ pub unsafe fn get_global_setting(key: &str) -> NixideResult<String> {
/// This function is intentionally marked unsafe to discourage its use. /// This function is intentionally marked unsafe to discourage its use.
/// Please prefer [nixide::FlakeSettings] and [nixide::FetchersSettings]. /// Please prefer [nixide::FlakeSettings] and [nixide::FetchersSettings].
/// ///
pub unsafe fn set_global_setting(key: &str, value: &str) -> NixideResult<()> { pub unsafe fn set_global_setting<S: AsRef<str>, T: AsRef<str>>(
let c_key = CString::new(key).to_nixide_result()?; key: S,
let c_value = CString::new(value).to_nixide_result()?; value: T,
) -> NixideResult<()> {
let key = key.as_c_ptr()?;
let value = value.as_c_ptr()?;
wrap::nix_fn!(|ctx: &ErrorContext| unsafe { wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_setting_set(ctx.as_ptr(), c_key.as_ptr(), c_value.as_ptr()); sys::nix_setting_set(ctx.as_ptr(), key, value);
}) })
} }

View file

@ -1,7 +1,6 @@
use std::ffi::CString;
use crate::NixideResult; use crate::NixideResult;
use crate::errors::{ErrorContext, ToNixideResult as _}; use crate::errors::ErrorContext;
use crate::stdext::AsCPtr as _;
use crate::util::wrap; use crate::util::wrap;
use crate::util::wrappers::AsInnerPtr as _; use crate::util::wrappers::AsInnerPtr as _;
@ -12,8 +11,8 @@ pub fn load_plugins() -> NixideResult<()> {
} }
pub fn register_plugin<S: AsRef<str>>(path: S) -> NixideResult<()> { pub fn register_plugin<S: AsRef<str>>(path: S) -> NixideResult<()> {
let c_path = CString::new(path.as_ref()).to_nixide_result()?; let path_ptr = path.as_ref().into_c_ptr()?;
wrap::nix_fn!(|ctx: &ErrorContext| unsafe { wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_register_plugin(ctx.as_ptr(), c_path.as_ptr().cast_mut()); sys::nix_register_plugin(ctx.as_ptr(), path_ptr);
}) })
} }

View file

@ -5,6 +5,33 @@ use std::str::from_utf8;
use crate::NixideResult; use crate::NixideResult;
use crate::errors::new_nixide_error; use crate::errors::new_nixide_error;
pub trait AsCPtr<T> {
#[allow(unused)]
fn as_c_ptr(&self) -> NixideResult<*const T>;
#[allow(unused)]
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 { pub trait CCharPtrExt {
#[allow(unused)] #[allow(unused)]
fn to_utf8_string(self) -> NixideResult<String>; fn to_utf8_string(self) -> NixideResult<String>;

View file

@ -1,5 +1,5 @@
mod cchar_ptr; mod cchar_ptr;
mod slice; mod slice;
pub(crate) use cchar_ptr::CCharPtrExt; pub(crate) use cchar_ptr::{AsCPtr, CCharPtrExt};
pub(crate) use slice::SliceExt; pub(crate) use slice::SliceExt;

View file

@ -8,13 +8,14 @@ mod path;
pub use path::*; pub use path::*;
use std::cell::RefCell; use std::cell::RefCell;
use std::ffi::{CString, c_char, c_void}; use std::ffi::{c_char, c_void};
use std::path::PathBuf; use std::path::PathBuf;
use std::ptr::{NonNull, null, null_mut}; use std::ptr::{NonNull, null, null_mut};
use std::rc::Rc; use std::rc::Rc;
use crate::NixideResult; use crate::NixideResult;
use crate::errors::{ErrorContext, ToNixideResult as _}; use crate::errors::ErrorContext;
use crate::stdext::AsCPtr as _;
use crate::sys; use crate::sys;
use crate::util::wrap; use crate::util::wrap;
use crate::util::wrappers::AsInnerPtr; use crate::util::wrappers::AsInnerPtr;
@ -57,8 +58,7 @@ impl Store {
/// Returns an error if the store cannot be opened. /// Returns an error if the store cannot be opened.
/// ///
pub fn open(uri: &str) -> NixideResult<Rc<RefCell<Self>>> { pub fn open(uri: &str) -> NixideResult<Rc<RefCell<Self>>> {
let c_uri = CString::new(uri).to_nixide_result()?; unsafe { Self::open_ptr(uri.as_c_ptr()?) }
unsafe { Self::open_ptr(c_uri.as_ptr()) }
} }
/// Opens a connection to the default Nix store. /// Opens a connection to the default Nix store.

View file

@ -79,8 +79,8 @@ impl StorePath {
/// use nixide::{Store, StorePath}; /// use nixide::{Store, StorePath};
/// ///
/// fn main() { /// fn main() {
/// let storeref = Store::default().unwrap(); /// let store_ref = Store::default().unwrap();
/// let path = StorePath::new(storeref, "/nix/store/f7gmvzd74wc1vlxzjdqy0af2381g8wr6-nix-manual-2.31.2-man").unwrap(); /// let path = StorePath::new("/nix/store/f7gmvzd74wc1vlxzjdqy0af2381g8wr6-nix-manual-2.31.2-man").unwrap();
/// } /// }
/// ``` /// ```
/// ///