From 7e53302a0912b357c1be3d40f9aa04599082c95f Mon Sep 17 00:00:00 2001 From: _cry64 Date: Fri, 3 Apr 2026 21:19:12 +1000 Subject: [PATCH 1/5] hide rustfmt.toml --- rustfmt.toml => .rustfmt.toml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename rustfmt.toml => .rustfmt.toml (100%) diff --git a/rustfmt.toml b/.rustfmt.toml similarity index 100% rename from rustfmt.toml rename to .rustfmt.toml From 3580e3528714ed6f776a9515bf1d7cd80f42b5ae Mon Sep 17 00:00:00 2001 From: _cry64 Date: Fri, 3 Apr 2026 21:19:30 +1000 Subject: [PATCH 2/5] ensure libnixide is optimised for release --- nixide-sys/build.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/nixide-sys/build.rs b/nixide-sys/build.rs index 59bd10e..19c9e23 100644 --- a/nixide-sys/build.rs +++ b/nixide-sys/build.rs @@ -137,6 +137,7 @@ fn main() { .file("libnixide-c/nixide_api_flake.cc") .file("libnixide-c/nixide_api_fetchers.cc") // .files(LIBS.iter().map(|s| (*s).strip_prefix("nix-").unwrap().strip_suffix("-c").unwrap())) + .opt_level((!cfg!(debug_assertions)) as u32 * 3) .includes(&include_paths) .compile("libnixide"); From 47c79e7d535084bcfcbdd256d1befefde190ddde Mon Sep 17 00:00:00 2001 From: _cry64 Date: Fri, 3 Apr 2026 21:19:53 +1000 Subject: [PATCH 3/5] fix Store::realise returning empty --- nixide/src/store/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nixide/src/store/mod.rs b/nixide/src/store/mod.rs index f40a395..a2dc000 100644 --- a/nixide/src/store/mod.rs +++ b/nixide/src/store/mod.rs @@ -108,7 +108,7 @@ impl Store { /// /// Returns an error if the path cannot be realized. /// - pub fn realise( + pub fn realise( &self, path: &StorePath, user_callback: fn(&str, &StorePath), @@ -130,7 +130,7 @@ impl Store { let callback = unsafe { (*userdata).inner }; callback(output_name.as_ref(), &store_path); - (output_name, store_path); + (unsafe {(*userdata).retval }).append((output_name, store_path)); }, |callback, state: *mut __UserData, @@ -139,6 +139,8 @@ impl Store { // WARNING: Using `write` instead of assignment via `=` // WARNING: to not call `drop` on the old, uninitialized value. (&raw mut (*state).inner).write(user_callback); + // register return value + (&raw mut (*state).retval).write(Vec::new()); sys::nix_store_realise( ctx.as_ptr(), From d70e6240fa01043f6781f18d07a313a74297cb67 Mon Sep 17 00:00:00 2001 From: _cry64 Date: Fri, 3 Apr 2026 21:21:00 +1000 Subject: [PATCH 4/5] StorePath should expect Rc --- nixide/src/store/path.rs | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/nixide/src/store/path.rs b/nixide/src/store/path.rs index 40c139b..5eed4fd 100644 --- a/nixide/src/store/path.rs +++ b/nixide/src/store/path.rs @@ -1,6 +1,8 @@ +use std::cell::RefCell; use std::ffi::{CString, c_void}; use std::path::PathBuf; use std::ptr::NonNull; +use std::rc::Rc; use super::Store; use crate::NixideResult; @@ -15,7 +17,8 @@ use crate::util::wrappers::AsInnerPtr; /// Represents a store path that can be realized, queried, or manipulated. /// pub struct StorePath { - pub(crate) inner: NonNull, + inner: NonNull, + store: Rc>, } impl Clone for StorePath { @@ -25,7 +28,10 @@ impl Clone for StorePath { panic_issue_call_failed!("nix_store_path_clone returned None for valid path") }); - StorePath { inner } + StorePath { + inner, + store: self.store.clone(), + } } } @@ -65,17 +71,17 @@ impl StorePath { /// # Errors /// /// Returns an error if the path cannot be parsed. - pub fn parse(store: &Store, path: &str) -> NixideResult { + pub fn parse(store: Rc>, path: &str) -> NixideResult { let c_path = CString::new(path).or(Err(new_nixide_error!(StringNulByte)))?; let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe { - sys::nix_store_parse_path(ctx.as_ptr(), store.as_ptr(), c_path.as_ptr()) + sys::nix_store_parse_path(ctx.as_ptr(), store.borrow().as_ptr(), c_path.as_ptr()) })?; - Ok(Self { inner }) + Ok(Self { inner, store }) } - pub fn fake_path(store: &Store) -> NixideResult { + pub fn fake_path(store: Rc>) -> NixideResult { Self::parse(store, "/nix/store/00000000000000000000000000000000-fake") } @@ -108,22 +114,18 @@ impl StorePath { /// Not all types of stores support this operation. /// /// # Arguments - /// * `context` [in] - Optional, stores error information - /// * `store` [in] - nix store reference - /// * `path` [in] - the path to get the real path from - /// * `callback` [in] - called with the real path - /// * `user_data` [in] - arbitrary data, passed to the callback when it's called. + /// * `store` - nix store reference /// /// # Arguments /// /// * `store` - The store containing the path /// - pub fn real_path(&self, store: &Store) -> NixideResult { + pub fn real_path(&self) -> NixideResult { wrap::nix_pathbuf_callback!( |callback, userdata: *mut __UserData, ctx: &ErrorContext| unsafe { sys::nix_store_real_path( ctx.as_ptr(), - store.inner.as_ptr(), + self.store.borrow().as_ptr(), self.as_ptr(), Some(callback), userdata as *mut c_void, From 4beda8850fdb7bd3713046f43e989f5cd2aea47f Mon Sep 17 00:00:00 2001 From: _cry64 Date: Fri, 3 Apr 2026 21:21:09 +1000 Subject: [PATCH 5/5] add StorePath::with_closure --- nixide/src/store/path.rs | 62 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/nixide/src/store/path.rs b/nixide/src/store/path.rs index 5eed4fd..417d2f4 100644 --- a/nixide/src/store/path.rs +++ b/nixide/src/store/path.rs @@ -147,4 +147,66 @@ impl StorePath { }) .is_ok() } + + /// Gets the closure of a specific store path + /// + /// The callback borrows each StorePath only for the duration of the call. + /// + /// # Arguments + /// + /// * flip - If false, compute the forward closure (paths referenced by any store path in the closure). + /// If true, compute the backward closure (paths that reference any store path in the closure). + /// * include_outputs - If flip_direction is false: for any derivation in the closure, include its outputs. + /// If flip_direction is true: for any output in the closure, include derivations that produce it. + /// * include_derivers - If flip_direction is false: for any output in the closure, include the derivation that + /// produced it. + /// If flip_direction is true: for any derivation in the closure, include its outputs. + /// * user_callback - The function to call for every store path, in no particular order + /// + pub fn with_closure( + &self, + flip: bool, + include_outputs: bool, + include_derivers: bool, + user_callback: fn(&StorePath), + ) -> NixideResult<()> { + wrap::nix_callback!( + |context: *mut sys::NixCContext, + ; userdata: (Rc>, fn(&StorePath)); + store_path: *const sys::StorePath, + | -> () { + let callback: fn(&StorePath) = unsafe { (*userdata).inner.1 }; + let store = unsafe { (*userdata).inner.0.clone() }; + + let path = &StorePath { + inner: NonNull::new(unsafe { store.borrow().as_ptr() } as *mut sys::StorePath).unwrap(), + store, + }; + + callback(&path); + }, + |callback, + state: *mut __UserData, + ctx: &ErrorContext| unsafe { + // register userdata + // WARNING: Using `write` instead of assignment via `=` + // WARNING: to not call `drop` on the old, uninitialized value. + (&raw mut (*state).inner).write((self.store.clone(), user_callback)); + + sys::nix_store_get_fs_closure( + ctx.as_ptr(), + self.store.borrow().as_ptr(), + self.as_ptr(), + flip, + include_outputs, + include_derivers, + (*state).inner_ptr() as *mut c_void, + Some(callback)); + } + ) + } + + // XXX: TODO: nix 2.34.4 adds a LOT here (ie especially around derivations) + // XXX: TODO: it also removes nix_store_path* functions (ie nix_store_path_free)? + // XXX: TODO: why?? try and research this, maybe they didn't mean to?? }