From fee35fa88bbfa2b05f273036a151f6861e0d9320 Mon Sep 17 00:00:00 2001 From: _cry64 Date: Mon, 30 Mar 2026 12:48:43 +1000 Subject: [PATCH] fix bad usage of sys::nix_gc_incref --- Cargo.lock | 356 ++++++++++++++++++ nixide/Cargo.toml | 1 + nixide/src/errors/context.rs | 74 ++-- nixide/src/expr/eval_state.rs | 53 +-- nixide/src/expr/eval_state_builder.rs | 48 ++- nixide/src/expr/realised_string.rs | 25 +- nixide/src/expr/tests.rs | 34 +- nixide/src/expr/values/attrs.rs | 55 ++- nixide/src/expr/values/bool.rs | 28 +- nixide/src/expr/values/float.rs | 27 +- nixide/src/expr/values/function.rs | 46 ++- nixide/src/expr/values/int.rs | 27 +- nixide/src/expr/values/list.rs | 47 ++- nixide/src/expr/values/mod.rs | 32 +- nixide/src/expr/values/null.rs | 30 +- nixide/src/expr/values/path.rs | 28 +- nixide/src/expr/values/string.rs | 27 +- nixide/src/expr/values/thunk.rs | 41 +- nixide/src/flake/eval_state_builder_ext.rs | 14 - nixide/src/flake/fetchers_settings.rs | 54 ++- nixide/src/flake/flake_lock_flags.rs | 139 ++++--- nixide/src/flake/flake_reference.rs | 95 +++-- .../src/flake/flake_reference_parse_flags.rs | 73 ++-- nixide/src/flake/flake_settings.rs | 87 ++--- nixide/src/flake/locked_flake.rs | 345 +++++++++-------- nixide/src/flake/mod.rs | 8 +- nixide/src/init.rs | 29 +- nixide/src/lib.rs | 2 + nixide/src/nix_settings.rs | 37 ++ nixide/src/store/mod.rs | 94 ++--- nixide/src/store/path.rs | 48 ++- nixide/src/store/tests.rs | 37 +- 32 files changed, 1359 insertions(+), 682 deletions(-) delete mode 100644 nixide/src/flake/eval_state_builder_ext.rs diff --git a/Cargo.lock b/Cargo.lock index eec43ca..154a81f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + [[package]] name = "bindgen" version = "0.72.1" @@ -118,12 +124,40 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + [[package]] name = "find-msvc-tools" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "futures-core" version = "0.3.32" @@ -159,12 +193,64 @@ dependencies = [ "slab", ] +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + [[package]] name = "glob" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + [[package]] name = "itertools" version = "0.13.0" @@ -174,6 +260,18 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "libc" version = "0.2.183" @@ -190,6 +288,12 @@ dependencies = [ "windows-link", ] +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + [[package]] name = "lock_api" version = "0.4.14" @@ -226,6 +330,7 @@ dependencies = [ "nixide-sys", "serial_test", "stdext", + "tempfile", ] [[package]] @@ -290,6 +395,16 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "proc-macro2" version = "1.0.106" @@ -308,6 +423,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "redox_syscall" version = "0.5.18" @@ -352,6 +473,19 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + [[package]] name = "scc" version = "2.4.0" @@ -373,6 +507,54 @@ version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "490dcfcbfef26be6800d11870ff2df8774fa6e86d047e3e8c8a76b25655e41ca" +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "serial_test" version = "3.4.0" @@ -434,20 +616,194 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom", + "once_cell", + "rustix", + "windows-sys", +] + [[package]] name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + [[package]] name = "yap" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfe269e7b803a5e8e20cbd97860e136529cd83bf2c9c6d37b142467e7e1f051f" + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/nixide/Cargo.toml b/nixide/Cargo.toml index 3832ebc..345f42f 100644 --- a/nixide/Cargo.toml +++ b/nixide/Cargo.toml @@ -23,6 +23,7 @@ libc = "0.2.183" stdext = "0.3.3" ctor = "0.6.3" nixide-sys = { path = "../nixide-sys", version = "0.1.0", features = ["nix-util-c", "nix-main-c"]} +tempfile = "3.27.0" [dev-dependencies] serial_test = "3.4.0" diff --git a/nixide/src/errors/context.rs b/nixide/src/errors/context.rs index 2ab2227..786daec 100644 --- a/nixide/src/errors/context.rs +++ b/nixide/src/errors/context.rs @@ -10,14 +10,14 @@ // * These may be rendered differently, so that users can distinguish them. // */ // bool isFromExpr = false; - +// // /** // * Exit status. // */ // unsigned int status = 1; - +// // Suggestions suggestions; - +// // static std::optional programName; // }; @@ -67,6 +67,19 @@ pub(crate) struct ErrorContext { inner: NonNull, } +// impl Clone for ErrorContext { +// 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 } +// } +// } + impl AsInnerPtr for ErrorContext { #[inline] unsafe fn as_ptr(&self) -> *mut sys::nix_c_context { @@ -183,7 +196,6 @@ impl ErrorContext { /// 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; @@ -218,11 +230,9 @@ impl ErrorContext { /// This function **never fails**. /// fn get_err(&self) -> Option { - let err = unsafe { sys::nix_err_code(self.as_ptr()) }; - - match err { + match unsafe { sys::nix_err_code(self.as_ptr()) } { sys::nix_err_NIX_OK => None, - _ => Some(err), + err => Some(err), } } @@ -257,13 +267,17 @@ impl ErrorContext { /// and avoid passing in a [sys::nix_c_context] struct. /// fn get_msg(&self) -> Option { - let ctx = ErrorContext::new(); - unsafe { - // NOTE: an Err here only occurs when `self.get_code() == Ok(())` - let mut n: c_uint = 0; + // NOTE: an Err here only occurs when `self.get_code() == Ok(())` + let mut n: c_uint = 0; + let result = wrap::nix_fn!(|ctx: &ErrorContext| unsafe { sys::nix_err_msg(ctx.as_ptr(), self.as_ptr(), &mut n) .to_utf8_string_n(n as usize) .ok() + }); + + match result { + Ok(option) => option, + Err(_) => None, } } @@ -305,19 +319,18 @@ impl ErrorContext { /// ``` /// fn get_nix_err_name(&self) -> Option { - #[allow(unused_unsafe)] // XXX: TODO: remove this `unused_unsafe` - unsafe { - // NOTE: an Err here only occurs when "Last error was not a nix error" - wrap::nix_string_callback!(|callback, userdata: *mut __UserData, ctx: &ErrorContext| { + // NOTE: an Err here only occurs when "Last error was not a nix error" + wrap::nix_string_callback!( + |callback, userdata: *mut __UserData, ctx: &ErrorContext| unsafe { sys::nix_err_name( ctx.as_ptr(), self.as_ptr(), Some(callback), userdata as *mut c_void, ) - }) - .ok() - } + } + ) + .ok() } /// Returns [None] if [self.code] is [sys::nix_err_NIX_OK], and [Some] otherwise. @@ -358,19 +371,16 @@ impl ErrorContext { /// ``` /// fn get_nix_err_info_msg(&self) -> Option { - #[allow(unused_unsafe)] // XXX: TODO: remove this `unused_unsafe` - unsafe { - // NOTE: an Err here only occurs when "Last error was not a nix error" - wrap::nix_string_callback!(|callback, userdata, ctx: &ErrorContext| { - sys::nix_err_info_msg( - ctx.as_ptr(), - self.as_ptr(), - Some(callback), - userdata as *mut c_void, - ) - }) - .ok() - } + // NOTE: an Err here only occurs when "Last error was not a nix error" + wrap::nix_string_callback!(|callback, userdata, ctx: &ErrorContext| unsafe { + sys::nix_err_info_msg( + ctx.as_ptr(), + self.as_ptr(), + Some(callback), + userdata as *mut c_void, + ) + }) + .ok() } } diff --git a/nixide/src/expr/eval_state.rs b/nixide/src/expr/eval_state.rs index 3818d1a..c491642 100644 --- a/nixide/src/expr/eval_state.rs +++ b/nixide/src/expr/eval_state.rs @@ -1,8 +1,5 @@ -use std::cell::RefCell; -use std::ffi::CString; +use std::ffi::{CString, c_void}; use std::ptr::NonNull; -use std::rc::Rc; -use std::sync::Arc; use crate::errors::new_nixide_error; @@ -18,46 +15,56 @@ use crate::{NixideResult, Store}; /// This provides the main interface for evaluating Nix expressions /// and creating values. pub struct EvalState { - inner: Rc>>, + inner: NonNull, - // XXX: TODO: is an `Arc` necessary or just a `Store` - store: Arc, + store: 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 for EvalState { #[inline] unsafe fn as_ptr(&self) -> *mut sys::EvalState { - self.inner.borrow().as_ptr() + self.inner.as_ptr() } #[inline] unsafe fn as_ref(&self) -> &sys::EvalState { - unsafe { self.inner.borrow().as_ref() } + unsafe { self.inner.as_ref() } } #[inline] unsafe fn as_mut(&mut self) -> &mut sys::EvalState { - unsafe { self.inner.borrow_mut().as_mut() } + unsafe { self.inner.as_mut() } } } impl EvalState { /// Construct a new EvalState directly from its attributes - pub(super) fn new(inner: NonNull, store: Arc) -> Self { + /// + pub(super) fn new(inner: NonNull, store: &Store) -> Self { Self { - inner: Rc::new(RefCell::new(inner)), - store, + inner, + store: store.clone(), } } - #[inline] - pub(crate) fn inner_ref(&self) -> Rc>> { - self.inner.clone() - } - - #[inline] - pub(crate) unsafe fn store_ref(&self) -> &Store { - self.store.as_ref() + pub fn store_ref(&self) -> &Store { + &self.store } /// Evaluate a Nix expression from a string. @@ -70,7 +77,7 @@ impl EvalState { /// # Errors /// /// Returns an error if evaluation fails. - pub fn eval_from_string(&self, expr: &str, path: &str) -> NixideResult { + pub fn interpret(&self, expr: &str, path: &str) -> NixideResult { let expr_c = CString::new(expr).or(Err(new_nixide_error!(StringNulByte)))?; let path_c = CString::new(path).or(Err(new_nixide_error!(StringNulByte)))?; @@ -92,7 +99,7 @@ impl EvalState { ); value }) - .map(|ptr| Value::from((ptr, self.inner_ref()))) + .map(|ptr| Value::from((ptr, self))) } } diff --git a/nixide/src/expr/eval_state_builder.rs b/nixide/src/expr/eval_state_builder.rs index de2672b..ee3faeb 100644 --- a/nixide/src/expr/eval_state_builder.rs +++ b/nixide/src/expr/eval_state_builder.rs @@ -1,6 +1,5 @@ -use std::ffi::{CString, c_char}; +use std::ffi::{CString, c_char, c_void}; use std::ptr::{self, NonNull}; -use std::sync::Arc; use super::EvalState; #[cfg(feature = "flakes")] @@ -15,11 +14,28 @@ use crate::util::{panic_issue_call_failed, wrap}; /// /// This allows configuring the evaluation environment before creating /// the evaluation state. +/// pub struct EvalStateBuilder { inner: NonNull, - store: Arc, + store: Store, } +// impl Clone for EvalStateBuilder { +// 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 for EvalStateBuilder { #[inline] unsafe fn as_ptr(&self) -> *mut sys::nix_eval_state_builder { @@ -47,17 +63,15 @@ impl EvalStateBuilder { /// # Errors /// /// Returns an error if the builder cannot be created. - pub fn new(store: &Arc) -> NixideResult { + /// + pub fn new(store: &Store) -> NixideResult { let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe { sys::nix_eval_state_builder_new(ctx.as_ptr(), store.as_ptr()) })?; - // sys::nix_eval_state_builder_load(context, builder); - // sys::nix_flake_settings_add_to_eval_state_builder(context, settings, builder); - Ok(EvalStateBuilder { inner, - store: Arc::clone(store), + store: store.clone(), }) } @@ -66,18 +80,20 @@ impl EvalStateBuilder { /// # Errors /// /// Returns an error if the evaluation state cannot be built. + /// pub fn build(self) -> NixideResult { // Build the state let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe { sys::nix_eval_state_build(ctx.as_ptr(), self.as_ptr()) })?; - Ok(EvalState::new(inner, self.store.clone())) + Ok(EvalState::new(inner, &self.store)) } - // XXX: TODO + // XXX: TODO: use `flakes()` instead + #[deprecated] #[cfg(feature = "flakes")] - fn set_flake_settings(self, settings: FlakeSettings) -> NixideResult { + pub fn set_flake_settings(self, settings: &FlakeSettings) -> NixideResult { wrap::nix_fn!(|ctx: &ErrorContext| unsafe { sys::nix_flake_settings_add_to_eval_state_builder( ctx.as_ptr(), @@ -89,7 +105,13 @@ impl EvalStateBuilder { Ok(self) } - fn load_ambient_settings(self) -> NixideResult { + #[cfg(feature = "flakes")] + pub fn flakes(self) -> NixideResult { + #[allow(deprecated)] + self.set_flake_settings(&FlakeSettings::new()?) + } + + pub fn load_ambient_settings(self) -> NixideResult { wrap::nix_fn!(|ctx: &ErrorContext| unsafe { sys::nix_eval_state_builder_load(ctx.as_ptr(), self.as_ptr()); })?; @@ -97,7 +119,7 @@ impl EvalStateBuilder { Ok(self) } - fn set_lookup_path>(self, paths: Vec

) -> NixideResult { + pub fn set_lookup_path>(self, paths: Vec

) -> NixideResult { let paths_len = paths.len(); let paths_capacity = paths.capacity(); diff --git a/nixide/src/expr/realised_string.rs b/nixide/src/expr/realised_string.rs index acae8c1..5d5e08f 100644 --- a/nixide/src/expr/realised_string.rs +++ b/nixide/src/expr/realised_string.rs @@ -1,13 +1,13 @@ use std::cell::RefCell; -use std::ffi::c_char; +use std::ffi::{c_char, c_void}; use std::ptr::NonNull; use crate::errors::ErrorContext; use crate::expr::values::NixString; use crate::stdext::CCharPtrExt; use crate::sys; -use crate::util::wrappers::AsInnerPtr; use crate::util::LazyArray; +use crate::util::wrappers::AsInnerPtr; use crate::util::{panic_issue_call_failed, wrap}; use crate::{EvalState, NixideResult, StorePath}; @@ -17,6 +17,23 @@ pub struct RealisedString<'a> { pub children: LazyArray StorePath + 'a>>, } +// impl<'a> Clone for RealisedString<'a> { +// 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, +// path: self.path.clone(), +// children: self.children, +// } +// } +// } + impl<'a> AsInnerPtr for RealisedString<'a> { #[inline] unsafe fn as_ptr(&self) -> *mut sys::nix_realised_string { @@ -81,7 +98,7 @@ impl<'a> RealisedString<'a> { path: Self::parse_path(inner.as_ptr(), state), children: LazyArray::new( size, - Box::new(|_| StorePath::fake_path(unsafe { state.store_ref() }).unwrap()), + Box::new(|_| StorePath::fake_path(state.store_ref()).unwrap()), ), }) } @@ -98,7 +115,7 @@ impl<'a> RealisedString<'a> { err ) }); - StorePath::parse(unsafe { state.store_ref() }, &path_str).unwrap_or_else(|err| { + StorePath::parse(state.store_ref(), &path_str).unwrap_or_else(|err| { panic_issue_call_failed!( "`sys::nix_realised_string_get_buffer_(start|size)` invalid store path ({})", err diff --git a/nixide/src/expr/tests.rs b/nixide/src/expr/tests.rs index 0b32729..5233ea2 100644 --- a/nixide/src/expr/tests.rs +++ b/nixide/src/expr/tests.rs @@ -1,4 +1,4 @@ -use std::sync::Arc; +use std::rc::Rc; use serial_test::serial; @@ -8,7 +8,7 @@ use crate::Store; #[test] #[serial] fn test_eval_state_builder() { - let store = Arc::new(Store::open(None).expect("Failed to open store")); + let store = Rc::new(Store::default().expect("Failed to open store")); let _state = EvalStateBuilder::new(&store) .expect("Failed to create builder") .build() @@ -19,14 +19,14 @@ fn test_eval_state_builder() { #[test] #[serial] fn test_simple_evaluation() { - let store = Arc::new(Store::open(None).expect("Failed to open store")); + let store = Rc::new(Store::default().expect("Failed to open store")); let state = EvalStateBuilder::new(&store) .expect("Failed to create builder") .build() .expect("Failed to build state"); let result = state - .eval_from_string("1 + 2", "") + .interpret("1 + 2", "") .expect("Failed to evaluate expression"); assert!(matches!(result, Value::Int(_))); @@ -40,7 +40,7 @@ fn test_simple_evaluation() { #[test] #[serial] fn test_value_types() { - let store = Arc::new(Store::open(None).expect("Failed to open store")); + let store = Store::default().expect("Failed to open store"); let state = EvalStateBuilder::new(&store) .expect("Failed to create builder") .build() @@ -48,7 +48,7 @@ fn test_value_types() { // Test integer let int_val = state - .eval_from_string("42", "") + .interpret("42", "") .expect("Failed to evaluate int"); assert!(matches!(int_val, Value::Int(_))); if let Value::Int(value) = int_val { @@ -59,7 +59,7 @@ fn test_value_types() { // Test boolean let bool_val = state - .eval_from_string("true", "") + .interpret("true", "") .expect("Failed to evaluate bool"); assert!(matches!(bool_val, Value::Bool(_))); if let Value::Bool(value) = bool_val { @@ -70,7 +70,7 @@ fn test_value_types() { // Test string let string_val = state - .eval_from_string("\"hello\"", "") + .interpret("\"hello\"", "") .expect("Failed to evaluate string"); assert!(matches!(string_val, Value::String(_))); if let Value::String(value) = string_val { @@ -83,7 +83,7 @@ fn test_value_types() { #[test] #[serial] fn test_value_formatting() { - let store = Arc::new(Store::open(None).expect("Failed to open store")); + let store = Store::default().expect("Failed to open store"); let state = EvalStateBuilder::new(&store) .expect("Failed to create builder") .build() @@ -91,27 +91,27 @@ fn test_value_formatting() { // Test integer formatting let int_val = state - .eval_from_string("42", "") + .interpret("42", "") .expect("Failed to evaluate int"); assert_eq!(format!("{int_val}"), "42"); assert_eq!(format!("{int_val:?}"), "Value::Int(NixInt(42))"); // Test boolean formatting let true_val = state - .eval_from_string("true", "") + .interpret("true", "") .expect("Failed to evaluate bool"); assert_eq!(format!("{true_val}"), "true"); assert_eq!(format!("{true_val:?}"), "Value::Bool(NixBool(true))"); let false_val = state - .eval_from_string("false", "") + .interpret("false", "") .expect("Failed to evaluate bool"); assert_eq!(format!("{false_val}"), "false"); assert_eq!(format!("{false_val:?}"), "Value::Bool(NixBool(false))"); // Test string formatting let str_val = state - .eval_from_string("\"hello world\"", "") + .interpret("\"hello world\"", "") .expect("Failed to evaluate string"); assert_eq!(format!("{str_val}"), "hello world"); assert_eq!( @@ -121,7 +121,7 @@ fn test_value_formatting() { // Test string with quotes let quoted_str = state - .eval_from_string("\"say \\\"hello\\\"\"", "") + .interpret("\"say \\\"hello\\\"\"", "") .expect("Failed to evaluate quoted string"); assert_eq!(format!("{quoted_str}"), "say \"hello\""); assert_eq!( @@ -131,14 +131,14 @@ fn test_value_formatting() { // Test null formatting let null_val = state - .eval_from_string("null", "") + .interpret("null", "") .expect("Failed to evaluate null"); assert_eq!(format!("{null_val}"), "null"); assert_eq!(format!("{null_val:?}"), "Value::Null(NixNull)"); // Test collection formatting let attrs_val = state - .eval_from_string("{ a = 1; }", "") + .interpret("{ a = 1; }", "") .expect("Failed to evaluate attrs"); assert_eq!(format!("{attrs_val}"), "{ }"); assert_eq!( @@ -147,7 +147,7 @@ fn test_value_formatting() { ); let list_val = state - .eval_from_string("[ 1 2 3 ]", "") + .interpret("[ 1 2 3 ]", "") .expect("Failed to evaluate list"); assert_eq!(format!("{list_val}"), "[ ]"); assert_eq!(format!("{list_val:?}"), "Value::List(NixList([ ]))"); diff --git a/nixide/src/expr/values/attrs.rs b/nixide/src/expr/values/attrs.rs index 4baacd0..e0ab6a0 100644 --- a/nixide/src/expr/values/attrs.rs +++ b/nixide/src/expr/values/attrs.rs @@ -1,22 +1,38 @@ -use std::cell::RefCell; +use std::ffi::c_void; use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; use std::ptr::{self, NonNull}; -use std::rc::Rc; use super::{NixThunk, NixValue, Value}; -use crate::NixError; use crate::errors::{ErrorContext, NixideError}; use crate::stdext::{AsCPtr, CCharPtrExt}; use crate::sys; use crate::util::wrappers::AsInnerPtr; use crate::util::{panic_issue_call_failed, wrap}; +use crate::{EvalState, NixError}; pub struct NixAttrs { inner: NonNull, - state: Rc>>, + state: EvalState, len: u32, } +impl Clone for NixAttrs { + 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, + state: self.state.clone(), + len: self.len, + } + } +} + impl Drop for NixAttrs { fn drop(&mut self) { let ctx = ErrorContext::new(); @@ -61,13 +77,17 @@ impl NixValue for NixAttrs { sys::ValueType_NIX_TYPE_ATTRS } - fn from(inner: NonNull, state: Rc>>) -> Self { + fn from(inner: NonNull, state: &EvalState) -> Self { let len = wrap::nix_fn!(|ctx: &ErrorContext| unsafe { sys::nix_get_attrs_size(ctx.as_ptr(), inner.as_ptr()) }) .unwrap_or_else(|err| panic_issue_call_failed!("{}", err)); - Self { inner, state, len } + Self { + inner, + state: state.clone(), + len, + } } } @@ -88,7 +108,7 @@ impl NixAttrs { sys::nix_get_attr_byidx( ctx.as_ptr(), self.as_ptr(), - self.state.borrow_mut().as_ptr(), + self.state.as_ptr(), index, name_ptr, ) @@ -99,7 +119,7 @@ impl NixAttrs { .to_utf8_string() .unwrap_or_else(|err| panic_issue_call_failed!("{}", err)); - let value = Value::from((inner, self.state.clone())); + let value = Value::from((inner, &self.state)); Some((name, value)) } @@ -115,7 +135,7 @@ impl NixAttrs { sys::nix_get_attr_byidx_lazy( ctx.as_ptr(), self.as_ptr(), - self.state.borrow_mut().as_ptr(), + self.state.as_ptr(), index, name_ptr, ) @@ -126,7 +146,7 @@ impl NixAttrs { .to_utf8_string() .unwrap_or_else(|err| panic_issue_call_failed!("{}", err)); - let value = ::from(inner, self.state.clone()); + let value = ::from(inner, &self.state); Some((name, value)) } @@ -137,12 +157,7 @@ impl NixAttrs { } let name_ptr = wrap::nix_fn!(|ctx: &ErrorContext| unsafe { - sys::nix_get_attr_name_byidx( - ctx.as_ptr(), - self.as_ptr(), - self.state.borrow_mut().as_ptr(), - index, - ) + sys::nix_get_attr_name_byidx(ctx.as_ptr(), self.as_ptr(), self.state.as_ptr(), index) }) .unwrap_or_else(|err| panic_issue_call_failed!("{}", err)); @@ -161,7 +176,7 @@ impl NixAttrs { sys::nix_get_attr_byname( ctx.as_ptr(), self.as_ptr(), - self.state.borrow_mut().as_ptr(), + self.state.as_ptr(), name.as_ref() .into_c_ptr() .unwrap_or_else(|err| panic_issue_call_failed!("{}", err)), @@ -169,7 +184,7 @@ impl NixAttrs { }); match result { - Ok(inner) => Some(Value::from((inner, self.state.clone()))), + Ok(inner) => Some(Value::from((inner, &self.state))), Err(NixideError::NixError { err: NixError::KeyNotFound(_), @@ -187,7 +202,7 @@ impl NixAttrs { sys::nix_get_attr_byname_lazy( ctx.as_ptr(), self.as_ptr(), - self.state.borrow_mut().as_ptr(), + self.state.as_ptr(), name.as_ref() .into_c_ptr() .unwrap_or_else(|err| panic_issue_call_failed!("{}", err)), @@ -195,7 +210,7 @@ impl NixAttrs { }); match result { - Ok(inner) => Some(::from(inner, self.state.clone())), + Ok(inner) => Some(::from(inner, &self.state)), Err(NixideError::NixError { err: NixError::KeyNotFound(_), diff --git a/nixide/src/expr/values/bool.rs b/nixide/src/expr/values/bool.rs index 01f5718..e400bf0 100644 --- a/nixide/src/expr/values/bool.rs +++ b/nixide/src/expr/values/bool.rs @@ -1,21 +1,37 @@ -use std::cell::RefCell; +use std::ffi::c_void; use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; use std::ptr::NonNull; -use std::rc::Rc; use super::NixValue; use crate::errors::ErrorContext; -use crate::sys; use crate::util::panic_issue_call_failed; use crate::util::wrap; use crate::util::wrappers::AsInnerPtr; +use crate::{EvalState, sys}; pub struct NixBool { inner: NonNull, - state: Rc>>, + state: EvalState, value: bool, } +impl Clone for NixBool { + 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, + state: self.state.clone(), + value: self.value, + } + } +} + impl Drop for NixBool { fn drop(&mut self) { let ctx = ErrorContext::new(); @@ -60,7 +76,7 @@ impl NixValue for NixBool { sys::ValueType_NIX_TYPE_BOOL } - fn from(inner: NonNull, state: Rc>>) -> Self { + fn from(inner: NonNull, state: &EvalState) -> Self { let value = wrap::nix_fn!(|ctx: &ErrorContext| unsafe { sys::nix_get_bool(ctx.as_ptr(), inner.as_ptr()) }) @@ -70,7 +86,7 @@ impl NixValue for NixBool { Self { inner, - state, + state: state.clone(), value, } } diff --git a/nixide/src/expr/values/float.rs b/nixide/src/expr/values/float.rs index b47569b..59c52ab 100644 --- a/nixide/src/expr/values/float.rs +++ b/nixide/src/expr/values/float.rs @@ -1,9 +1,9 @@ -use std::cell::RefCell; +use std::ffi::c_void; use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; use std::ptr::NonNull; -use std::rc::Rc; use super::NixValue; +use crate::EvalState; use crate::errors::ErrorContext; use crate::sys; use crate::util::wrappers::AsInnerPtr; @@ -11,10 +11,27 @@ use crate::util::{panic_issue_call_failed, wrap}; pub struct NixFloat { inner: NonNull, - state: Rc>>, + state: EvalState, value: f64, } +impl Clone for NixFloat { + 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, + state: self.state.clone(), + value: self.value, + } + } +} + impl Drop for NixFloat { fn drop(&mut self) { let ctx = ErrorContext::new(); @@ -59,7 +76,7 @@ impl NixValue for NixFloat { sys::ValueType_NIX_TYPE_FLOAT } - fn from(inner: NonNull, state: Rc>>) -> Self { + fn from(inner: NonNull, state: &EvalState) -> Self { let value = wrap::nix_fn!(|ctx: &ErrorContext| unsafe { sys::nix_get_float(ctx.as_ptr(), inner.as_ptr()) }) @@ -69,7 +86,7 @@ impl NixValue for NixFloat { Self { inner, - state, + state: state.clone(), value, } } diff --git a/nixide/src/expr/values/function.rs b/nixide/src/expr/values/function.rs index 98827b1..4cc08d7 100644 --- a/nixide/src/expr/values/function.rs +++ b/nixide/src/expr/values/function.rs @@ -1,19 +1,33 @@ -use std::cell::RefCell; +use std::ffi::c_void; use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; use std::ptr::NonNull; -use std::rc::Rc; use super::{NixValue, Value}; use crate::errors::ErrorContext; use crate::stdext::SliceExt; -use crate::sys; use crate::util::wrappers::AsInnerPtr; use crate::util::{panic_issue_call_failed, wrap}; +use crate::{EvalState, sys}; pub struct NixFunction { inner: NonNull, - state: Rc>>, - value: i64, + state: EvalState, +} + +impl Clone for NixFunction { + 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, + state: self.state.clone(), + } + } } impl Drop for NixFunction { @@ -60,16 +74,10 @@ impl NixValue for NixFunction { sys::ValueType_NIX_TYPE_FUNCTION } - fn from(inner: NonNull, state: Rc>>) -> Self { - let value = wrap::nix_fn!(|ctx: &ErrorContext| unsafe { - sys::nix_get_int(ctx.as_ptr(), inner.as_ptr()) - }) - .unwrap_or_else(|err| panic_issue_call_failed!("{}", err)); - + fn from(inner: NonNull, state: &EvalState) -> Self { Self { inner, - state, - value, + state: state.clone(), } } } @@ -80,14 +88,14 @@ impl NixFunction { T: NixValue, { let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe { - sys::nix_alloc_value(ctx.as_ptr(), self.state.borrow().as_ptr()) + sys::nix_alloc_value(ctx.as_ptr(), self.state.as_ptr()) }) .unwrap_or_else(|err| panic_issue_call_failed!("{}", err)); wrap::nix_fn!(|ctx: &ErrorContext| unsafe { sys::nix_value_call( ctx.as_ptr(), - self.state.borrow().as_ptr(), + self.state.as_ptr(), self.as_ptr(), arg.as_ptr(), inner.as_ptr(), @@ -95,7 +103,7 @@ impl NixFunction { }) .unwrap_or_else(|err| panic_issue_call_failed!("{}", err)); - Value::from((inner, self.state.clone())) + Value::from((inner, &self.state)) } pub fn call_many(&self, args: &[&T]) -> Value @@ -103,14 +111,14 @@ impl NixFunction { T: NixValue, { let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe { - sys::nix_alloc_value(ctx.as_ptr(), self.state.borrow().as_ptr()) + sys::nix_alloc_value(ctx.as_ptr(), self.state.as_ptr()) }) .unwrap_or_else(|err| panic_issue_call_failed!("{}", err)); wrap::nix_fn!(|ctx: &ErrorContext| unsafe { sys::nix_value_call_multi( ctx.as_ptr(), - self.state.borrow().as_ptr(), + self.state.as_ptr(), self.as_ptr(), args.len(), args.into_c_array(), @@ -119,7 +127,7 @@ impl NixFunction { }) .unwrap_or_else(|err| panic_issue_call_failed!("{}", err)); - Value::from((inner, self.state.clone())) + Value::from((inner, &self.state)) } } diff --git a/nixide/src/expr/values/int.rs b/nixide/src/expr/values/int.rs index 4ddd147..e783e3c 100644 --- a/nixide/src/expr/values/int.rs +++ b/nixide/src/expr/values/int.rs @@ -1,9 +1,9 @@ -use std::cell::RefCell; +use std::ffi::c_void; use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; use std::ptr::NonNull; -use std::rc::Rc; use super::NixValue; +use crate::EvalState; use crate::errors::ErrorContext; use crate::sys; use crate::util::wrappers::AsInnerPtr; @@ -11,10 +11,27 @@ use crate::util::{panic_issue_call_failed, wrap}; pub struct NixInt { inner: NonNull, - state: Rc>>, + state: EvalState, value: i64, } +impl Clone for NixInt { + 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, + state: self.state.clone(), + value: self.value, + } + } +} + impl Drop for NixInt { fn drop(&mut self) { let ctx = ErrorContext::new(); @@ -59,7 +76,7 @@ impl NixValue for NixInt { sys::ValueType_NIX_TYPE_INT } - fn from(inner: NonNull, state: Rc>>) -> Self { + fn from(inner: NonNull, state: &EvalState) -> Self { let value = wrap::nix_fn!(|ctx: &ErrorContext| unsafe { sys::nix_get_int(ctx.as_ptr(), inner.as_ptr()) }) @@ -67,7 +84,7 @@ impl NixValue for NixInt { Self { inner, - state, + state: state.clone(), value, } } diff --git a/nixide/src/expr/values/list.rs b/nixide/src/expr/values/list.rs index fb82bc7..001e971 100644 --- a/nixide/src/expr/values/list.rs +++ b/nixide/src/expr/values/list.rs @@ -1,9 +1,9 @@ -use std::cell::RefCell; +use std::ffi::c_void; use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; use std::ptr::NonNull; -use std::rc::Rc; use super::{NixThunk, NixValue, Value}; +use crate::EvalState; use crate::errors::ErrorContext; use crate::sys; use crate::util::wrappers::AsInnerPtr; @@ -11,7 +11,23 @@ use crate::util::{panic_issue_call_failed, wrap}; pub struct NixList { inner: NonNull, - state: Rc>>, + state: EvalState, +} + +impl Clone for NixList { + 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, + state: self.state.clone(), + } + } } impl Drop for NixList { @@ -58,8 +74,11 @@ impl NixValue for NixList { sys::ValueType_NIX_TYPE_LIST } - fn from(inner: NonNull, state: Rc>>) -> Self { - Self { inner, state } + fn from(inner: NonNull, state: &EvalState) -> Self { + Self { + inner, + state: state.clone(), + } } } @@ -98,29 +117,19 @@ impl NixList { pub fn get(&self, index: u32) -> Value { let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe { - sys::nix_get_list_byidx( - ctx.as_ptr(), - self.as_ptr(), - self.state.borrow().as_ptr(), - index, - ) + sys::nix_get_list_byidx(ctx.as_ptr(), self.as_ptr(), self.state.as_ptr(), index) }) .unwrap_or_else(|err| panic_issue_call_failed!("{}", err)); - Value::from((inner, self.state.clone())) + Value::from((inner, &self.state)) } pub fn get_lazy(&self, index: u32) -> NixThunk { let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe { - sys::nix_get_list_byidx_lazy( - ctx.as_ptr(), - self.as_ptr(), - self.state.borrow().as_ptr(), - index, - ) + sys::nix_get_list_byidx_lazy(ctx.as_ptr(), self.as_ptr(), self.state.as_ptr(), index) }) .unwrap_or_else(|err| panic_issue_call_failed!("{}", err)); - ::from(inner, self.state.clone()) + ::from(inner, &self.state) } } diff --git a/nixide/src/expr/values/mod.rs b/nixide/src/expr/values/mod.rs index 6b1f459..f6f6b80 100644 --- a/nixide/src/expr/values/mod.rs +++ b/nixide/src/expr/values/mod.rs @@ -23,10 +23,8 @@ pub use path::NixPath; pub use string::NixString; pub use thunk::NixThunk; -use std::cell::RefCell; use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; use std::ptr::NonNull; -use std::rc::Rc; use crate::EvalState; use crate::errors::ErrorContext; @@ -40,12 +38,12 @@ use crate::sys::{ use crate::util::wrappers::AsInnerPtr; use crate::util::{panic_issue_call_failed, wrap}; -pub trait NixValue: Drop + Display + Debug + AsInnerPtr { +pub trait NixValue: Clone + Drop + Display + Debug + AsInnerPtr { /// TODO fn type_id(&self) -> sys::ValueType; /// TODO - fn from(inner: NonNull, state: Rc>>) -> Self; + fn from(inner: NonNull, state: &EvalState) -> Self; } /// A Nix value @@ -111,22 +109,12 @@ pub enum Value { // Failed(NixFailed), } -impl - From<( - NonNull, - Rc>>, - )> for Value -{ - fn from( - value: ( - NonNull, - Rc>>, - ), - ) -> Self { +impl From<(NonNull, &EvalState)> for Value { + fn from(value: (NonNull, &EvalState)) -> Self { let (inner, state) = value; wrap::nix_fn!(|ctx: &ErrorContext| unsafe { - sys::nix_value_force(ctx.as_ptr(), state.borrow().as_ptr(), inner.as_ptr()) + sys::nix_value_force(ctx.as_ptr(), state.as_ptr(), inner.as_ptr()) }) .unwrap_or_else(|err| panic_issue_call_failed!("{}", err)); @@ -197,13 +185,3 @@ impl Debug for Value { } } } - -// macro_rules! is_type { -// ($expr:expr, $tt:tt) => {{ -// match $expr { -// $tt => true, -// _ => false, -// } -// }}; -// } -// pub(self) use is_type; diff --git a/nixide/src/expr/values/null.rs b/nixide/src/expr/values/null.rs index 11440de..7ac8ecc 100644 --- a/nixide/src/expr/values/null.rs +++ b/nixide/src/expr/values/null.rs @@ -1,16 +1,33 @@ -use std::cell::RefCell; +use std::ffi::c_void; use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; use std::ptr::NonNull; -use std::rc::Rc; use super::NixValue; +use crate::EvalState; use crate::errors::ErrorContext; use crate::sys; +use crate::util::wrap; use crate::util::wrappers::AsInnerPtr; pub struct NixNull { inner: NonNull, - state: Rc>>, + state: EvalState, +} + +impl Clone for NixNull { + 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, + state: self.state.clone(), + } + } } impl Drop for NixNull { @@ -57,7 +74,10 @@ impl NixValue for NixNull { sys::ValueType_NIX_TYPE_NULL } - fn from(inner: NonNull, state: Rc>>) -> Self { - Self { inner, state } + fn from(inner: NonNull, state: &EvalState) -> Self { + Self { + inner, + state: state.clone(), + } } } diff --git a/nixide/src/expr/values/path.rs b/nixide/src/expr/values/path.rs index b25dfa6..066808e 100644 --- a/nixide/src/expr/values/path.rs +++ b/nixide/src/expr/values/path.rs @@ -1,23 +1,39 @@ -use std::cell::RefCell; +use std::ffi::c_void; use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; use std::path::PathBuf; use std::ptr::NonNull; -use std::rc::Rc; use super::NixValue; use crate::errors::ErrorContext; use crate::stdext::CCharPtrExt; -use crate::sys; use crate::util::panic_issue_call_failed; use crate::util::wrap; use crate::util::wrappers::AsInnerPtr; +use crate::{EvalState, sys}; pub struct NixPath { inner: NonNull, - state: Rc>>, + state: EvalState, value: PathBuf, } +impl Clone for NixPath { + 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, + state: self.state.clone(), + value: self.value.clone(), + } + } +} + impl Drop for NixPath { fn drop(&mut self) { let ctx = ErrorContext::new(); @@ -62,7 +78,7 @@ impl NixValue for NixPath { sys::ValueType_NIX_TYPE_PATH } - fn from(inner: NonNull, state: Rc>>) -> Self { + fn from(inner: NonNull, state: &EvalState) -> Self { let value = wrap::nix_fn!(|ctx: &ErrorContext| unsafe { sys::nix_get_path_string(ctx.as_ptr(), inner.as_ptr()) }) @@ -72,7 +88,7 @@ impl NixValue for NixPath { Self { inner, - state, + state: state.clone(), value, } } diff --git a/nixide/src/expr/values/string.rs b/nixide/src/expr/values/string.rs index 93ec66d..658599b 100644 --- a/nixide/src/expr/values/string.rs +++ b/nixide/src/expr/values/string.rs @@ -1,22 +1,37 @@ -use std::cell::RefCell; use std::ffi::c_void; use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; use std::ptr::NonNull; -use std::rc::Rc; use super::NixValue; use crate::errors::ErrorContext; -use crate::sys; use crate::util::panic_issue_call_failed; use crate::util::wrap; use crate::util::wrappers::AsInnerPtr; +use crate::{EvalState, sys}; pub struct NixString { inner: NonNull, - state: Rc>>, + state: EvalState, value: String, } +impl Clone for NixString { + 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, + state: self.state.clone(), + value: self.value.clone(), + } + } +} + impl Drop for NixString { fn drop(&mut self) { let ctx = ErrorContext::new(); @@ -61,7 +76,7 @@ impl NixValue for NixString { sys::ValueType_NIX_TYPE_STRING } - fn from(inner: NonNull, state: Rc>>) -> Self { + fn from(inner: NonNull, state: &EvalState) -> Self { let value = wrap::nix_string_callback!( |callback, userdata: *mut __UserData, ctx: &ErrorContext| unsafe { sys::nix_get_string( @@ -76,7 +91,7 @@ impl NixValue for NixString { Self { inner, - state, + state: state.clone(), value, } } diff --git a/nixide/src/expr/values/thunk.rs b/nixide/src/expr/values/thunk.rs index 6327623..bc20cc8 100644 --- a/nixide/src/expr/values/thunk.rs +++ b/nixide/src/expr/values/thunk.rs @@ -1,9 +1,9 @@ -use std::cell::RefCell; +use std::ffi::c_void; use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; use std::ptr::NonNull; -use std::rc::Rc; use super::{NixValue, Value}; +use crate::EvalState; use crate::errors::ErrorContext; use crate::sys; use crate::util::wrappers::AsInnerPtr; @@ -11,7 +11,23 @@ use crate::util::{panic_issue_call_failed, wrap}; pub struct NixThunk { inner: NonNull, - state: Rc>>, + state: EvalState, +} + +impl Clone for NixThunk { + 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, + state: self.state.clone(), + } + } } impl Drop for NixThunk { @@ -58,26 +74,21 @@ impl NixValue for NixThunk { sys::ValueType_NIX_TYPE_THUNK } - fn from(inner: NonNull, state: Rc>>) -> Self { - Self { inner, state } + fn from(inner: NonNull, state: &EvalState) -> Self { + Self { + inner, + state: state.clone(), + } } } impl NixThunk { - // fn to_inner(self) -> NonNull { - // self.inner - // } - pub fn eval(self) -> Value { wrap::nix_fn!(|ctx: &ErrorContext| unsafe { - sys::nix_value_force( - ctx.as_ptr(), - self.state.borrow().as_ptr(), - self.inner.as_ptr(), - ) + sys::nix_value_force(ctx.as_ptr(), self.state.as_ptr(), self.inner.as_ptr()) }) .unwrap_or_else(|err| panic_issue_call_failed!("{}", err)); - Value::from((self.inner, self.state.to_owned())) + Value::from((self.inner, &self.state)) } } diff --git a/nixide/src/flake/eval_state_builder_ext.rs b/nixide/src/flake/eval_state_builder_ext.rs deleted file mode 100644 index ff8598f..0000000 --- a/nixide/src/flake/eval_state_builder_ext.rs +++ /dev/null @@ -1,14 +0,0 @@ -use super::FlakeSettings; -use crate::{EvalStateBuilder, NixideError}; - -pub trait EvalStateBuilderExt { - /// Configures the eval state to provide flakes features such as `builtins.getFlake`. - fn flakes(self, settings: &FlakeSettings) -> Result; -} - -impl EvalStateBuilderExt for EvalStateBuilder { - /// Configures the eval state to provide flakes features such as `builtins.getFlake`. - fn flakes(mut self, settings: &FlakeSettings) -> Result { - settings.add_to_eval_state_builder(&mut self).map(|_| self) - } -} diff --git a/nixide/src/flake/fetchers_settings.rs b/nixide/src/flake/fetchers_settings.rs index ac4f5ca..1f24d04 100644 --- a/nixide/src/flake/fetchers_settings.rs +++ b/nixide/src/flake/fetchers_settings.rs @@ -1,28 +1,39 @@ +use std::ffi::c_void; use std::ptr::NonNull; -use crate::errors::{new_nixide_error, ErrorContext}; +use crate::NixideResult; +use crate::errors::ErrorContext; use crate::sys; +use crate::util::wrap; use crate::util::wrappers::AsInnerPtr; -use crate::NixideError; -pub(super) struct FetchersSettings { - pub(super) ptr: NonNull, +pub struct FetchersSettings { + inner: NonNull, } impl FetchersSettings { - pub fn new() -> Result { - let ctx = ErrorContext::new(); - let ptr = unsafe { sys::nix_fetchers_settings_new(ctx.as_ptr()) }; - Ok(FetchersSettings { - ptr: NonNull::new(ptr).ok_or(new_nixide_error!(NullPtr))?, - }) - } + pub fn new() -> NixideResult { + let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe { + sys::nix_fetchers_settings_new(ctx.as_ptr()) + })?; - pub(crate) unsafe fn as_ptr(&self) -> *mut sys::nix_fetchers_settings { - self.ptr.as_ptr() + Ok(Self { inner }) } } +// 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 { fn drop(&mut self) { unsafe { @@ -31,6 +42,23 @@ impl Drop for FetchersSettings { } } +impl AsInnerPtr for FetchersSettings { + #[inline] + unsafe fn as_ptr(&self) -> *mut sys::nix_fetchers_settings { + self.inner.as_ptr() + } + + #[inline] + unsafe fn as_ref(&self) -> &sys::nix_fetchers_settings { + unsafe { self.inner.as_ref() } + } + + #[inline] + unsafe fn as_mut(&mut self) -> &mut sys::nix_fetchers_settings { + unsafe { self.inner.as_mut() } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/nixide/src/flake/flake_lock_flags.rs b/nixide/src/flake/flake_lock_flags.rs index bb066ec..8b3985a 100644 --- a/nixide/src/flake/flake_lock_flags.rs +++ b/nixide/src/flake/flake_lock_flags.rs @@ -1,22 +1,26 @@ -use std::ffi::CString; +use std::ffi::c_void; use std::ptr::NonNull; use super::{FlakeReference, FlakeSettings}; -use crate::errors::new_nixide_error; +use crate::NixideResult; use crate::errors::ErrorContext; +use crate::stdext::AsCPtr as _; use crate::sys; +use crate::util::wrap; use crate::util::wrappers::AsInnerPtr; -use crate::NixideError; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub enum FlakeLockMode { /// Configures [LockedFlake::lock] to make incremental changes to the lock file as needed. Changes are written to file. + /// WriteAsNeeded, /// Like [FlakeLockMode::WriteAsNeeded], but does not write to the lock file. + /// Virtual, /// Make [LockedFlake::lock] check if the lock file is up to date. If not, an error is returned. + /// Check, } @@ -24,6 +28,20 @@ pub enum FlakeLockMode { pub struct FlakeLockFlags { pub(crate) inner: NonNull, } + +// impl Clone for FlakeLockFlags { +// 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 FlakeLockFlags { fn drop(&mut self) { unsafe { @@ -31,69 +49,49 @@ impl Drop for FlakeLockFlags { } } } -impl FlakeLockFlags { - // XXX: TODO: what is the default FlakeLockMode? - pub fn new(settings: &FlakeSettings) -> Result { - let ctx = ErrorContext::new(); - NonNull::new(unsafe { sys::nix_flake_lock_flags_new(ctx.as_ptr(), settings.as_ptr()) }) - .ok_or(new_nixide_error!(NullPtr)) - .map(|inner| FlakeLockFlags { inner }) - } - pub(crate) fn as_ptr(&self) -> *mut sys::nix_flake_lock_flags { +impl AsInnerPtr for FlakeLockFlags { + #[inline] + unsafe fn as_ptr(&self) -> *mut sys::nix_flake_lock_flags { self.inner.as_ptr() } - pub fn set_lock_mode(&mut self, mode: &FlakeLockMode) -> Result<(), NixideError> { - let ctx = ErrorContext::new(); - 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()) - }, - }; - match ctx.peak() { - Some(err) => Err(err), - None => Ok(()), - } + #[inline] + unsafe fn as_ref(&self) -> &sys::nix_flake_lock_flags { + unsafe { self.inner.as_ref() } } - /// Configures [LockedFlake::lock] to make incremental changes to the lock file as needed. Changes are written to file. - // pub fn set_mode_write_as_needed(&mut self) -> Result<(), NixideError> { - // ErrorContext::new().and_then(|ctx| { - // NixideError::from( - // unsafe { - // sys::nix_flake_lock_flags_set_mode_write_as_needed(ctx.as_ptr(), self.as_ptr()) - // }, - // "nix_flake_lock_flags_set_mode_write_as_needed", - // ) - // }) - // } + #[inline] + unsafe fn as_mut(&mut self) -> &mut sys::nix_flake_lock_flags { + unsafe { self.inner.as_mut() } + } +} - /// Make [LockedFlake::lock] check if the lock file is up to date. If not, an error is returned. - // pub fn set_mode_check(&mut self) -> Result<(), NixideError> { - // ErrorContext::new().and_then(|ctx| { - // NixideError::from( - // unsafe { sys::nix_flake_lock_flags_set_mode_check(ctx.as_ptr(), self.as_ptr()) }, - // "nix_flake_lock_flags_set_mode_check", - // ) - // }) - // } +impl FlakeLockFlags { + // XXX: TODO: what is the default FlakeLockMode? + pub fn new(settings: &FlakeSettings) -> NixideResult { + let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe { + sys::nix_flake_lock_flags_new(ctx.as_ptr(), settings.as_ptr()) + })?; - /// Like `set_mode_write_as_needed`, but does not write to the lock file. - // pub fn set_mode_virtual(&mut self) -> Result<(), NixideError> { - // ErrorContext::new().and_then(|ctx| { - // NixideError::from( - // unsafe { sys::nix_flake_lock_flags_set_mode_virtual(ctx.as_ptr(), self.as_ptr()) }, - // "nix_flake_lock_flags_set_mode_virtual", - // ) - // }) - // } + Ok(FlakeLockFlags { inner }) + } + + pub fn set_mode(&mut self, mode: &FlakeLockMode) -> NixideResult<()> { + 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()) + }, + }; + }) + } /// Adds an input override to the lock file that will be produced. /// The [LockedFlake::lock] operation will not write to the lock file. @@ -106,26 +104,17 @@ impl FlakeLockFlags { /// # Arguments /// /// * `path` - The input name/path to override (must not be empty) - /// * `flake_ref` - The flake reference to use as the override - pub fn override_input( - &mut self, - path: &str, - flakeref: &FlakeReference, - ) -> Result<(), NixideError> { - let input_path = CString::new(path).or_else(|_| Err(new_nixide_error!(StringNulByte))); + /// * `flakeref` - The flake reference to use as the override + pub fn override_input(&mut self, path: &str, flakeref: &FlakeReference) -> NixideResult<()> { + let input_path = path.as_c_ptr()?; - let ctx = ErrorContext::new(); - unsafe { + wrap::nix_fn!(|ctx: &ErrorContext| unsafe { sys::nix_flake_lock_flags_add_input_override( ctx.as_ptr(), self.as_ptr(), - input_path.as_ptr(), + input_path, flakeref.as_ptr(), - ) - }; - match ctx.peak() { - Some(err) => Err(err), - None => Ok(()), - } + ); + }) } } diff --git a/nixide/src/flake/flake_reference.rs b/nixide/src/flake/flake_reference.rs index c60a950..67ddf41 100644 --- a/nixide/src/flake/flake_reference.rs +++ b/nixide/src/flake/flake_reference.rs @@ -1,58 +1,99 @@ +use std::ffi::c_void; use std::os::raw::c_char; -use std::ptr::{null_mut, NonNull}; +use std::ptr::{NonNull, null_mut}; use super::{FetchersSettings, FlakeReferenceParseFlags, FlakeSettings}; -use crate::errors::new_nixide_error; -use crate::sys; -use crate::util::bindings::wrap_nix_string_callback; -use crate::util::wrappers::AsInnerPtr; use crate::NixideError; +use crate::errors::{ErrorContext, new_nixide_error}; +use crate::sys; +use crate::util::wrap; +use crate::util::wrappers::AsInnerPtr; +// XXX: TODO: rename FlakeReference -> FlakeRef pub struct FlakeReference { - pub(crate) ptr: NonNull, + inner: NonNull, + fragment: String, } +// 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 FlakeReference { fn drop(&mut self) { unsafe { - sys::nix_flake_reference_free(self.ptr.as_ptr()); + sys::nix_flake_reference_free(self.as_ptr()); } } } +impl AsInnerPtr for FlakeReference { + #[inline] + unsafe fn as_ptr(&self) -> *mut sys::nix_flake_reference { + self.inner.as_ptr() + } + + #[inline] + unsafe fn as_ref(&self) -> &sys::nix_flake_reference { + unsafe { self.inner.as_ref() } + } + + #[inline] + unsafe fn as_mut(&mut self) -> &mut sys::nix_flake_reference { + unsafe { self.inner.as_mut() } + } +} + impl FlakeReference { - pub fn as_ptr(&self) -> *mut sys::nix_flake_reference { - self.ptr.as_ptr() - } - /// 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 parse_with_fragment( + pub fn parse( fetch_settings: &FetchersSettings, flake_settings: &FlakeSettings, flags: &FlakeReferenceParseFlags, reference: &str, - ) -> Result<(FlakeReference, String), NixideError> { + ) -> Result { let mut ptr: *mut sys::nix_flake_reference = null_mut(); - let result = wrap_nix_string_callback(|ctx, callback, user_data| unsafe { - sys::nix_flake_reference_and_fragment_from_string( - ctx.as_ptr(), - fetch_settings.as_ptr(), - flake_settings.as_ptr(), - flags.as_ptr(), - reference.as_ptr() as *const c_char, - reference.len(), - &mut ptr, - Some(callback), - user_data, - ) - }); + 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(), + flags.as_ptr(), + reference.as_ptr() as *const c_char, + reference.len(), + &mut ptr, + Some(callback), + userdata as *mut c_void, + ) + } + )?; match NonNull::new(ptr) { - Some(ptr) => result.map(|s| (FlakeReference { ptr }, s)), + Some(inner) => Ok(FlakeReference { inner, fragment }), 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. + /// + #[inline] + #[allow(unused)] + pub fn fragment(&self) -> &str { + &self.fragment + } } diff --git a/nixide/src/flake/flake_reference_parse_flags.rs b/nixide/src/flake/flake_reference_parse_flags.rs index 39bbf78..cddf391 100644 --- a/nixide/src/flake/flake_reference_parse_flags.rs +++ b/nixide/src/flake/flake_reference_parse_flags.rs @@ -1,58 +1,77 @@ +use std::ffi::c_void; use std::os::raw::c_char; use std::ptr::NonNull; use super::FlakeSettings; -use crate::errors::{new_nixide_error, ErrorContext}; +use crate::NixideResult; +use crate::errors::ErrorContext; use crate::sys; +use crate::util::wrap; use crate::util::wrappers::AsInnerPtr; -use crate::NixideError; /// Parameters for parsing a flake reference. #[derive(Debug)] pub struct FlakeReferenceParseFlags { - pub(crate) ptr: NonNull, + inner: NonNull, } +// 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 FlakeReferenceParseFlags { fn drop(&mut self) { unsafe { - sys::nix_flake_reference_parse_flags_free(self.ptr.as_ptr()); + sys::nix_flake_reference_parse_flags_free(self.inner.as_ptr()); } } } +impl AsInnerPtr for FlakeReferenceParseFlags { + #[inline] + unsafe fn as_ptr(&self) -> *mut sys::nix_flake_reference_parse_flags { + self.inner.as_ptr() + } + + #[inline] + unsafe fn as_ref(&self) -> &sys::nix_flake_reference_parse_flags { + unsafe { self.inner.as_ref() } + } + + #[inline] + unsafe fn as_mut(&mut self) -> &mut sys::nix_flake_reference_parse_flags { + unsafe { self.inner.as_mut() } + } +} + impl FlakeReferenceParseFlags { - pub fn new(settings: &FlakeSettings) -> Result { - let ctx = ErrorContext::new(); - let ptr = - unsafe { sys::nix_flake_reference_parse_flags_new(ctx.as_ptr(), settings.as_ptr()) }; - match ctx.peak() { - Some(err) => Err(err), - None => NonNull::new(ptr).map_or(Err(new_nixide_error!(NullPtr)), |ptr| { - Ok(FlakeReferenceParseFlags { ptr }) - }), - } + pub fn new(settings: &FlakeSettings) -> NixideResult { + let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe { + sys::nix_flake_reference_parse_flags_new(ctx.as_ptr(), settings.as_ptr()) + })?; + + Ok(Self { inner }) } /// Sets the [base directory](https://nix.dev/manual/nix/latest/glossary#gloss-base-directory) /// for resolving local flake references. - pub fn set_base_directory(&mut self, base_directory: &str) -> Result<(), NixideError> { - let ctx = ErrorContext::new(); - unsafe { + pub fn set_base_directory(&mut self, base_directory: &str) -> NixideResult<()> { + wrap::nix_fn!(|ctx: &ErrorContext| unsafe { sys::nix_flake_reference_parse_flags_set_base_directory( ctx.as_ptr(), self.as_ptr(), base_directory.as_ptr() as *const c_char, base_directory.len(), - ) - }; - match ctx.peak() { - Some(err) => Err(err), - None => Ok(()), - } - } - - pub fn as_ptr(&self) -> *mut sys::nix_flake_reference_parse_flags { - self.ptr.as_ptr() + ); + }) } } diff --git a/nixide/src/flake/flake_settings.rs b/nixide/src/flake/flake_settings.rs index 3ef46da..295115b 100644 --- a/nixide/src/flake/flake_settings.rs +++ b/nixide/src/flake/flake_settings.rs @@ -1,52 +1,15 @@ +use std::ffi::c_void; use std::ptr::NonNull; -use crate::errors::{ErrorContext, new_nixide_error}; +use crate::NixideResult; +use crate::errors::ErrorContext; use crate::sys; +use crate::util::wrap; use crate::util::wrappers::AsInnerPtr; -use crate::{EvalStateBuilder, NixideError}; /// Store settings for the flakes feature. pub struct FlakeSettings { - pub(crate) inner: NonNull, -} - -impl AsInnerPtr for FlakeSettings { - unsafe fn as_ptr(&self) -> *mut sys::nix_flake_settings { - self.inner.as_ptr() - } -} - -impl FlakeSettings { - pub fn new() -> Result { - let ctx = ErrorContext::new(); - let opt = NonNull::new(unsafe { sys::nix_flake_settings_new(ctx.as_ptr()) }); - - match ctx.peak() { - Some(err) => Err(err), - None => match opt { - Some(inner) => Ok(FlakeSettings { inner }), - None => Err(new_nixide_error!(NullPtr)), - }, - } - } - - pub(super) fn add_to_eval_state_builder( - &self, - builder: &mut EvalStateBuilder, - ) -> Result<(), NixideError> { - let ctx = ErrorContext::new(); - unsafe { - sys::nix_flake_settings_add_to_eval_state_builder( - ctx.as_ptr(), - self.as_ptr(), - builder.as_ptr(), - ) - }; - match ctx.peak() { - Some(err) => Err(err), - None => Ok(()), - } - } + inner: NonNull, } impl Drop for FlakeSettings { @@ -56,3 +19,43 @@ impl Drop for FlakeSettings { } } } + +// impl Clone for FlakeSettings { +// 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 } +// } +// } + +impl AsInnerPtr for FlakeSettings { + #[inline] + unsafe fn as_ptr(&self) -> *mut sys::nix_flake_settings { + self.inner.as_ptr() + } + + #[inline] + unsafe fn as_ref(&self) -> &sys::nix_flake_settings { + unsafe { self.inner.as_ref() } + } + + #[inline] + unsafe fn as_mut(&mut self) -> &mut sys::nix_flake_settings { + unsafe { self.inner.as_mut() } + } +} + +impl FlakeSettings { + pub fn new() -> NixideResult { + let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe { + sys::nix_flake_settings_new(ctx.as_ptr()) + })?; + + Ok(Self { inner }) + } +} diff --git a/nixide/src/flake/locked_flake.rs b/nixide/src/flake/locked_flake.rs index f11732c..a2ae9af 100644 --- a/nixide/src/flake/locked_flake.rs +++ b/nixide/src/flake/locked_flake.rs @@ -1,145 +1,184 @@ +// XXX: TODO: find a way to read directly from FlakeSettings and FetchersSettings (the C++ classes) + +use std::ffi::c_void; use std::ptr::NonNull; use super::{FetchersSettings, FlakeLockFlags, FlakeReference, FlakeSettings}; -use crate::errors::{new_nixide_error, ErrorContext}; +use crate::errors::ErrorContext; use crate::sys; +use crate::util::wrap; use crate::util::wrappers::AsInnerPtr; -use crate::{EvalState, NixideError, Value}; +use crate::{EvalState, NixideResult, Value}; pub struct LockedFlake { - pub(crate) ptr: NonNull, + inner: NonNull, + + flakeref: FlakeReference, + state: EvalState, + flags: FlakeLockFlags, + fetch_settings: FetchersSettings, + flake_settings: FlakeSettings, } + +// impl Clone for LockedFlake { +// 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(), +// flakeref: self.flakeref.clone(), +// state: self.state.clone(), +// flags: self.flags.clone(), +// fetch_settings: self.fetch_settings.clone(), +// flake_settings: self.flake_settings.clone(), +// } +// } +// } + impl Drop for LockedFlake { fn drop(&mut self) { unsafe { - sys::nix_locked_flake_free(self.ptr.as_ptr()); + sys::nix_locked_flake_free(self.as_ptr()); } } } + +impl AsInnerPtr for LockedFlake { + #[inline] + unsafe fn as_ptr(&self) -> *mut sys::nix_locked_flake { + self.inner.as_ptr() + } + + #[inline] + unsafe fn as_ref(&self) -> &sys::nix_locked_flake { + unsafe { self.inner.as_ref() } + } + + #[inline] + unsafe fn as_mut(&mut self) -> &mut sys::nix_locked_flake { + unsafe { self.inner.as_mut() } + } +} + impl LockedFlake { pub fn lock( fetch_settings: &FetchersSettings, flake_settings: &FlakeSettings, - eval_state: &EvalState, + state: &EvalState, flags: &FlakeLockFlags, - flake_ref: &FlakeReference, - ) -> Result { - let ctx = ErrorContext::new(); - - let ptr = NonNull::new(unsafe { + flakeref: &FlakeReference, + ) -> NixideResult { + let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe { sys::nix_flake_lock( ctx.as_ptr(), fetch_settings.as_ptr(), flake_settings.as_ptr(), - eval_state.as_ptr(), + state.as_ptr(), flags.as_ptr(), - flake_ref.as_ptr(), + flakeref.as_ptr(), ) - }); + })?; - match ptr { - Some(ptr) => Ok(LockedFlake { ptr }), - None => Err(new_nixide_error!(NullPtr)), - } + Ok(Self { + inner, + flakeref: flakeref.clone(), + state: state.clone(), + flags: flags.clone(), + fetch_settings: fetch_settings.clone(), + flake_settings: flake_settings.clone(), + }) } /// Returns the outputs of the flake - the result of calling the `outputs` attribute. - pub fn outputs( - &self, - flake_settings: &FlakeSettings, - eval_state: &mut EvalState, - ) -> Result { - let ctx = ErrorContext::new(); - - let r = unsafe { + pub fn outputs(&self) -> NixideResult { + let value = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe { sys::nix_locked_flake_get_output_attrs( ctx.as_ptr(), - flake_settings.as_ptr(), - eval_state.as_ptr(), - self.ptr.as_ptr(), + self.flake_settings.as_ptr(), + self.state.as_ptr(), + self.inner.as_ptr(), ) - }; - Ok(nix_bindings_expr::value::__private::raw_value_new(r)) + })?; + + Ok(Value::from((value, &self.state))) } } #[cfg(test)] mod tests { - // use nix_bindings_expr::eval_state::{gc_register_my_thread, EvalStateBuilder}; - - use crate::flake::{FlakeLockMode, FlakeReferenceParseFlags}; - use crate::{EvalStateBuilder, Store}; - - use super::*; + use std::fs; use std::sync::Once; + use super::{FetchersSettings, FlakeLockFlags, FlakeReference, FlakeSettings, LockedFlake}; + use crate::flake::{FlakeLockMode, FlakeReferenceParseFlags}; + use crate::{EvalStateBuilder, Store, Value, set_global_setting}; + static INIT: Once = Once::new(); fn init() { // Only set experimental-features once to minimize the window where // concurrent Nix operations might read the setting while it's being modified - INIT.call_once(|| { - nix_bindings_expr::eval_state::init().unwrap(); - nix_bindings_util::settings::set("experimental-features", "flakes").unwrap(); + INIT.call_once(|| unsafe { + set_global_setting("experimental-features", "flakes").unwrap(); }); } #[test] fn flake_settings_getflake_exists() { init(); - let gc_registration = gc_register_my_thread(); - let store = Store::open(None, []).unwrap(); - let mut eval_state = EvalStateBuilder::new(store) + + let store = Store::default().expect("Failed to open store connection"); + let state = EvalStateBuilder::new(&store) .unwrap() - .flakes(&FlakeSettings::new().unwrap()) + .flakes() .unwrap() .build() .unwrap(); - let v = eval_state - .eval_from_string("builtins?getFlake", "") - .unwrap(); + let value = state.interpret("builtins?getFlake", "").unwrap(); - let b = eval_state.require_bool(&v).unwrap(); - - assert!(b); - - drop(gc_registration); + assert!(matches!(value, Value::Bool(_))); + if let Value::Bool(v) = value { + assert!(v.as_bool()); + } } #[test] fn flake_lock_load_flake() { init(); - let gc_registration = gc_register_my_thread(); - let store = Store::open(None, []).unwrap(); - let fetchers_settings = FetchersSettings::new().unwrap(); - let flake_settings = FlakeSettings::new().unwrap(); - let mut eval_state = EvalStateBuilder::new(store) - .unwrap() - .flakes(&flake_settings) - .unwrap() - .build() - .unwrap(); - - let tmp_dir = tempfile::tempdir().unwrap(); // Create flake.nix + let tmp_dir = tempfile::tempdir().unwrap(); let flake_nix = tmp_dir.path().join("flake.nix"); - std::fs::write( + fs::write( &flake_nix, r#" { outputs = { ... }: { - hello = "potato"; + hello = "world"; }; } "#, ) .unwrap(); + let store = Store::default().unwrap(); + let flake_settings = FlakeSettings::new().unwrap(); + + let mut eval_state = EvalStateBuilder::new(&store) + .unwrap() + .set_flake_settings(&flake_settings) + .unwrap() + .build() + .unwrap(); + + let fetchers_settings = FetchersSettings::new().unwrap(); let flake_lock_flags = FlakeLockFlags::new(&flake_settings).unwrap(); - let (flake_ref, fragment) = FlakeReference::parse_with_fragment( + let flakeref = FlakeReference::parse( &fetchers_settings, &flake_settings, &FlakeReferenceParseFlags::new(&flake_settings).unwrap(), @@ -147,41 +186,40 @@ mod tests { ) .unwrap(); - assert_eq!(fragment, "subthing"); + assert_eq!(flakeref.fragment(), "subthing"); let locked_flake = LockedFlake::lock( &fetchers_settings, &flake_settings, &eval_state, &flake_lock_flags, - &flake_ref, + &flakeref, ) .unwrap(); - let outputs = locked_flake - .outputs(&flake_settings, &mut eval_state) - .unwrap(); + let outputs = locked_flake.outputs().unwrap(); - let hello = eval_state.require_attrs_select(&outputs, "hello").unwrap(); - let hello = eval_state.require_string(&hello).unwrap(); + assert!(matches!(outputs, Value::Attrs(_))); + if let Value::Attrs(outputs) = outputs { + let value = outputs.get("hello").unwrap(); - assert_eq!(hello, "potato"); - - drop(fetchers_settings); - drop(tmp_dir); - drop(gc_registration); + assert!(matches!(value, Value::String(_))); + if let Value::String(value) = value { + assert_eq!(value.as_string(), "world"); + } + } } #[test] fn flake_lock_load_flake_with_flags() { init(); - let gc_registration = gc_register_my_thread(); - let store = Store::open(None, []).unwrap(); + + let store = Store::default().unwrap(); let fetchers_settings = FetchersSettings::new().unwrap(); let flake_settings = FlakeSettings::new().unwrap(); - let mut eval_state = EvalStateBuilder::new(store) + let mut eval_state = EvalStateBuilder::new(&store) .unwrap() - .flakes(&flake_settings) + .set_flake_settings(&flake_settings) .unwrap() .build() .unwrap(); @@ -222,7 +260,7 @@ mod tests { r#" { outputs = { ... }: { - hello = "BOB"; + hello = "ALICE"; }; } "#, @@ -251,7 +289,7 @@ mod tests { .set_base_directory(tmp_dir.path().to_str().unwrap()) .unwrap(); - let (flake_ref_a, fragment) = FlakeReference::parse_with_fragment( + let flakeref_a = FlakeReference::parse( &fetchers_settings, &flake_settings, &flake_reference_parse_flags, @@ -259,20 +297,17 @@ mod tests { ) .unwrap(); - assert_eq!(fragment, ""); + assert_eq!(flakeref_a.fragment(), ""); // Step 1: Do not update (check), fails - - flake_lock_flags - .set_lock_mode(&FlakeLockMode::Check) - .unwrap(); + flake_lock_flags.set_mode(&FlakeLockMode::Check).unwrap(); let locked_flake = LockedFlake::lock( &fetchers_settings, &flake_settings, &eval_state, &flake_lock_flags, - &flake_ref_a, + &flakeref_a, ); // Has not been locked and would need to write a lock file. assert!(locked_flake.is_err()); @@ -282,54 +317,50 @@ mod tests { }; // Step 2: Update but do not write, succeeds - flake_lock_flags - .set_lock_mode(&FlakeLockMode::Virtual) - .unwrap(); + flake_lock_flags.set_mode(&FlakeLockMode::Virtual).unwrap(); let locked_flake = LockedFlake::lock( &fetchers_settings, &flake_settings, &eval_state, &flake_lock_flags, - &flake_ref_a, + &flakeref_a, ) .unwrap(); - let outputs = locked_flake - .outputs(&flake_settings, &mut eval_state) - .unwrap(); + let outputs = locked_flake.outputs().unwrap(); - let hello = eval_state.require_attrs_select(&outputs, "hello").unwrap(); - let hello = eval_state.require_string(&hello).unwrap(); + assert!(matches!(outputs, Value::Attrs(_))); + if let Value::Attrs(outputs) = outputs { + let value = outputs.get("hello").unwrap(); - assert_eq!(hello, "BOB"); + assert!(matches!(value, Value::String(_))); + 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 - - flake_lock_flags - .set_lock_mode(&FlakeLockMode::Check) - .unwrap(); + flake_lock_flags.set_mode(&FlakeLockMode::Check).unwrap(); let locked_flake = LockedFlake::lock( &fetchers_settings, &flake_settings, &eval_state, &flake_lock_flags, - &flake_ref_a, + &flakeref_a, ); // Has not been locked and would need to write a lock file. - assert!(locked_flake.is_err()); match locked_flake { Ok(_) => panic!("Expected error, but got Ok"), Err(e) => { assert_eq!(e.to_string(), saved_err.to_string()); - } + }, }; // Step 4: Update and write, succeeds - flake_lock_flags - .set_lock_mode(&FlakeLockMode::WriteAsNeeded) + .set_mode(&FlakeLockMode::WriteAsNeeded) .unwrap(); let locked_flake = LockedFlake::lock( @@ -337,100 +368,110 @@ mod tests { &flake_settings, &eval_state, &flake_lock_flags, - &flake_ref_a, + &flakeref_a, ) .unwrap(); - let outputs = locked_flake - .outputs(&flake_settings, &mut eval_state) - .unwrap(); - let hello = eval_state.require_attrs_select(&outputs, "hello").unwrap(); - let hello = eval_state.require_string(&hello).unwrap(); - assert_eq!(hello, "BOB"); + 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"); + } + } // Step 5: Lock was written, so Step 1 succeeds - - flake_lock_flags - .set_lock_mode(&FlakeLockMode::Check) - .unwrap(); + flake_lock_flags.set_mode(&FlakeLockMode::Check).unwrap(); let locked_flake = LockedFlake::lock( &fetchers_settings, &flake_settings, &eval_state, &flake_lock_flags, - &flake_ref_a, + &flakeref_a, ) .unwrap(); - let outputs = locked_flake - .outputs(&flake_settings, &mut eval_state) - .unwrap(); - let hello = eval_state.require_attrs_select(&outputs, "hello").unwrap(); - let hello = eval_state.require_string(&hello).unwrap(); - assert_eq!(hello, "BOB"); + 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"); + } + } // Step 6: Lock with override, do not write // This shouldn't matter; write_as_needed will be overridden flake_lock_flags - .set_lock_mode(&FlakeLockMode::WriteAsNeeded) + .set_mode(&FlakeLockMode::WriteAsNeeded) .unwrap(); - let (flake_ref_c, fragment) = FlakeReference::parse_with_fragment( + let flakeref_c = FlakeReference::parse( &fetchers_settings, &flake_settings, &flake_reference_parse_flags, &format!("path:{}", &flake_dir_c_str), ) .unwrap(); - assert_eq!(fragment, ""); + assert_eq!(flakeref_c.fragment(), ""); - flake_lock_flags.override_input("b", &flake_ref_c).unwrap(); + flake_lock_flags.override_input("b", &flakeref_c).unwrap(); let locked_flake = LockedFlake::lock( &fetchers_settings, &flake_settings, &eval_state, &flake_lock_flags, - &flake_ref_a, + &flakeref_a, ) .unwrap(); - let outputs = locked_flake - .outputs(&flake_settings, &mut eval_state) - .unwrap(); - let hello = eval_state.require_attrs_select(&outputs, "hello").unwrap(); - let hello = eval_state.require_string(&hello).unwrap(); - assert_eq!(hello, "Claire"); + 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(), "Claire"); + } + } // Can't delete overrides, so trash it let mut flake_lock_flags = FlakeLockFlags::new(&flake_settings).unwrap(); // Step 7: Override was not written; lock still points to b - - flake_lock_flags - .set_lock_mode(&FlakeLockMode::Check) - .unwrap(); + flake_lock_flags.set_mode(&FlakeLockMode::Check).unwrap(); let locked_flake = LockedFlake::lock( &fetchers_settings, &flake_settings, &eval_state, &flake_lock_flags, - &flake_ref_a, + &flakeref_a, ) .unwrap(); - let outputs = locked_flake - .outputs(&flake_settings, &mut eval_state) - .unwrap(); - let hello = eval_state.require_attrs_select(&outputs, "hello").unwrap(); - let hello = eval_state.require_string(&hello).unwrap(); - assert_eq!(hello, "BOB"); + let outputs = locked_flake.outputs().unwrap(); - drop(fetchers_settings); - drop(tmp_dir); - drop(gc_registration); + 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"); + } + } } } diff --git a/nixide/src/flake/mod.rs b/nixide/src/flake/mod.rs index 9ae171f..314173e 100644 --- a/nixide/src/flake/mod.rs +++ b/nixide/src/flake/mod.rs @@ -5,9 +5,9 @@ mod flake_reference_parse_flags; mod flake_settings; mod locked_flake; -pub(self) use fetchers_settings::FetchersSettings; -pub(self) use flake_lock_flags::{FlakeLockFlags, FlakeLockMode}; -pub(self) use flake_reference::FlakeReference; -pub(self) use flake_reference_parse_flags::FlakeReferenceParseFlags; +use fetchers_settings::FetchersSettings; +use flake_lock_flags::{FlakeLockFlags, FlakeLockMode}; +use flake_reference::FlakeReference; +use flake_reference_parse_flags::FlakeReferenceParseFlags; pub use flake_settings::FlakeSettings; pub use locked_flake::LockedFlake; diff --git a/nixide/src/init.rs b/nixide/src/init.rs index cd9c484..7b85fb3 100644 --- a/nixide/src/init.rs +++ b/nixide/src/init.rs @@ -7,6 +7,14 @@ use super::util::wrappers::AsInnerPtr as _; pub(crate) static mut LIBNIX_INIT_STATUS: Option> = None; +/// Initialises the Nix `libutil` library's global state. +/// This function **should not be run directly!** `#[ctor]` ensures it runs at init-time. +/// +/// # Note +/// +/// `sys::nix_libexpr_init` internally runs `sys::nix_libutil_init` and `sys::nix_libstore_init`. +/// Hence this method isn't registered via `#[ctor]` if the `exprs` feature is enabled. +/// /// # Warning /// /// > Rust's philosophy is that nothing happens before or after main and [ctor](https://github.com/mmastrac/rust-ctor) @@ -16,7 +24,7 @@ pub(crate) static mut LIBNIX_INIT_STATUS: Option> = None; /// > - Excerpt from the [github:mmastrac/rust-ctor README.md](https://github.com/mmastrac/rust-ctor?tab=readme-ov-file#warnings) #[ctor] #[cfg(not(feature = "exprs"))] -fn init_libutil() { +pub(crate) fn init_libutil() { unsafe { if !matches!(LIBNIX_INIT_STATUS, Some(Err(_))) { LIBNIX_INIT_STATUS = Some(wrap::nix_fn!(|ctx: &ErrorContext| unsafe { @@ -26,6 +34,14 @@ fn init_libutil() { } } +/// Initialises the Nix `libstore` library's global state. +/// This function **should not be run directly!** `#[ctor]` ensures it runs at init-time. +/// +/// # Note +/// +/// `sys::nix_libexpr_init` internally runs `sys::nix_libutil_init` and `sys::nix_libstore_init`. +/// Hence this method isn't registered via `#[ctor]` if the `exprs` feature is enabled. +/// /// # Warning /// /// > Rust's philosophy is that nothing happens before or after main and [ctor](https://github.com/mmastrac/rust-ctor) @@ -35,7 +51,7 @@ fn init_libutil() { /// > - Excerpt from the [github:mmastrac/rust-ctor README.md](https://github.com/mmastrac/rust-ctor?tab=readme-ov-file#warnings) #[ctor] #[cfg(all(feature = "store", not(feature = "exprs")))] -fn init_libstore() { +pub(crate) fn init_libstore() { // XXX: TODO: how do I support `sys::nix_libstore_init_no_load_config(context)`? unsafe { if !matches!(LIBNIX_INIT_STATUS, Some(Err(_))) { @@ -46,7 +62,12 @@ fn init_libstore() { } } -/// `sys::nix_libexpr_init` internally runs +/// Initialises the Nix `libexpr` library's global state. +/// This function **should not be run directly!** `#[ctor]` ensures it runs at init-time. +/// +/// # Note +/// +/// `sys::nix_libexpr_init` internally runs `sys::nix_libutil_init` and `sys::nix_libstore_init`. /// /// # Warning /// @@ -57,7 +78,7 @@ fn init_libstore() { /// > - Excerpt from the [github:mmastrac/rust-ctor README.md](https://github.com/mmastrac/rust-ctor?tab=readme-ov-file#warnings) #[ctor] #[cfg(feature = "exprs")] -fn init_libexpr() { +pub(crate) fn init_libexpr() { unsafe { if !matches!(LIBNIX_INIT_STATUS, Some(Err(_))) { LIBNIX_INIT_STATUS = Some(wrap::nix_fn!(|ctx: &ErrorContext| unsafe { diff --git a/nixide/src/lib.rs b/nixide/src/lib.rs index c9407da..6b336f2 100644 --- a/nixide/src/lib.rs +++ b/nixide/src/lib.rs @@ -8,6 +8,7 @@ pub extern crate nixide_sys as sys; pub(crate) mod errors; mod init; +mod nix_settings; mod stdext; pub(crate) mod util; mod verbosity; @@ -21,6 +22,7 @@ mod flake; mod store; pub use errors::{NixError, NixideError, NixideResult}; +pub use nix_settings::{get_global_setting, set_global_setting}; pub use verbosity::{NixVerbosity, set_verbosity}; pub use version::NixVersion; diff --git a/nixide/src/nix_settings.rs b/nixide/src/nix_settings.rs index e69de29..21dd9a3 100644 --- a/nixide/src/nix_settings.rs +++ b/nixide/src/nix_settings.rs @@ -0,0 +1,37 @@ +use std::ffi::c_void; + +use crate::NixideResult; +use crate::errors::ErrorContext; +use crate::stdext::AsCPtr as _; +use crate::util::wrap; +use crate::util::wrappers::AsInnerPtr as _; + +/// # Note +/// This function is intentionally marked unsafe to discourage its use. +/// Please prefer [nixide::FlakeSettings] and [nixide::FetchersSettings]. +/// +pub unsafe fn get_global_setting>(key: S) -> NixideResult { + let key = key.as_c_ptr()?; + + wrap::nix_string_callback!( + |callback, userdata: *mut __UserData, ctx: &ErrorContext| unsafe { + sys::nix_setting_get(ctx.as_ptr(), key, Some(callback), userdata as *mut c_void); + } + ) +} + +/// # Note +/// This function is intentionally marked unsafe to discourage its use. +/// Please prefer [nixide::FlakeSettings] and [nixide::FetchersSettings]. +/// +pub unsafe fn set_global_setting, T: AsRef>( + key: S, + value: T, +) -> NixideResult<()> { + let key = key.as_c_ptr()?; + let value = value.as_c_ptr()?; + + wrap::nix_fn!(|ctx: &ErrorContext| unsafe { + sys::nix_setting_set(ctx.as_ptr(), key, value); + }) +} diff --git a/nixide/src/store/mod.rs b/nixide/src/store/mod.rs index 420d807..35c04e8 100644 --- a/nixide/src/store/mod.rs +++ b/nixide/src/store/mod.rs @@ -1,13 +1,4 @@ // XXX: TODO: should I add support for `nix_libstore_init_no_load_config` -// XXX: TODO: add support for nix_realised_string_* family of functions -// nix_realised_string_get_store_path -// nix_realised_string_get_store_path_count -// # nix_store_real_path -// # nix_store_is_valid_path -// # nix_store_get_version -// # nix_store_get_uri -// # nix_store_get_storedir -// # nix_store_copy_closure // nix_libstore_init_no_load_config #[cfg(test)] @@ -16,25 +7,38 @@ mod tests; mod path; pub use path::*; -use std::ffi::{c_char, c_void, CString}; +use std::ffi::{c_char, c_void}; use std::path::PathBuf; -use std::ptr::{null, null_mut, NonNull}; -use std::result::Result; +use std::ptr::{NonNull, null, null_mut}; -use crate::errors::{new_nixide_error, ErrorContext}; -use crate::stdext::CCharPtrExt; +use crate::NixideResult; +use crate::errors::ErrorContext; +use crate::stdext::{AsCPtr as _, CCharPtrExt as _}; use crate::sys; -use crate::util::wrap; use crate::util::wrappers::AsInnerPtr; -use crate::{NixideError, NixideResult}; +use crate::util::{panic_issue_call_failed, wrap}; /// Nix store for managing packages and derivations. /// /// The store provides access to Nix packages, derivations, and store paths. +/// pub struct Store { - pub(crate) inner: NonNull, + inner: NonNull, } +// impl Clone for Store { +// 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 } +// } +// } + impl AsInnerPtr for Store { #[inline] unsafe fn as_ptr(&self) -> *mut sys::Store { @@ -63,13 +67,19 @@ impl Store { /// # Errors /// /// Returns an error if the store cannot be opened. - pub fn open(uri: Option<&str>) -> Result { - let uri_ptr = match uri.map(CString::new) { - Some(Ok(c_uri)) => c_uri.as_ptr(), - Some(Err(_)) => Err(new_nixide_error!(StringNulByte))?, - None => null(), - }; + /// + pub fn open(uri: &str) -> NixideResult { + Self::open_ptr(uri.as_c_ptr()?) + } + /// Opens a connection to the default Nix store. + /// + pub fn default() -> NixideResult { + Self::open_ptr(null()) + } + + #[inline] + fn open_ptr(uri_ptr: *const c_char) -> NixideResult { let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe { // XXX: TODO: allow args to be parsed instead of just `null_mut` sys::nix_store_open(ctx.as_ptr(), uri_ptr, null_mut()) @@ -95,6 +105,7 @@ impl Store { /// # Errors /// /// Returns an error if the path cannot be realized. + /// pub fn realise( &self, path: &StorePath, @@ -107,11 +118,11 @@ impl Store { -> Vec<(String, StorePath)> { // XXX: TODO: test to see if this is ever null ("out" as a default feels unsafe...) // NOTE: this also ensures `output_name_ptr` isn't null - let output_name = output_name_ptr.to_utf8_string().expect("IDK1"); + let output_name = output_name_ptr.to_utf8_string().unwrap_or_else(|err| panic_issue_call_failed!("{}", err)); let inner = wrap::nix_ptr_fn!(|ctx| unsafe { sys::nix_store_path_clone(output_path_ptr as *mut sys::StorePath) - }).expect("IDK2"); + }).unwrap_or_else(|err| panic_issue_call_failed!("{}", err)); let store_path = StorePath { inner }; let callback = unsafe { (*userdata).inner }; @@ -161,14 +172,16 @@ impl Store { /// # Ok(()) /// # } /// ``` - pub fn store_path(&self, path: &str) -> Result { + /// + pub fn store_path(&self, path: &str) -> NixideResult { StorePath::parse(self, path) } /// Get the version of a Nix store /// /// If the store doesn't have a version (like the dummy store), returns None - pub fn version(&self) -> Result { + /// + pub fn version(&self) -> NixideResult { wrap::nix_string_callback!( |callback, userdata: *mut __UserData, ctx: &ErrorContext| unsafe { sys::nix_store_get_version( @@ -182,7 +195,8 @@ impl Store { } /// Get the URI of a Nix store - pub fn uri(&self) -> Result { + /// + pub fn uri(&self) -> NixideResult { wrap::nix_string_callback!( |callback, userdata: *mut __UserData, ctx: &ErrorContext| unsafe { sys::nix_store_get_uri( @@ -195,7 +209,7 @@ impl Store { ) } - pub fn store_dir(&self) -> Result { + pub fn store_dir(&self) -> NixideResult { wrap::nix_pathbuf_callback!( |callback, userdata: *mut __UserData, ctx: &ErrorContext| unsafe { sys::nix_store_get_storedir( @@ -208,34 +222,26 @@ impl Store { ) } - pub fn copy_closure_to( - &self, - dst_store: &Store, - store_path: &StorePath, - ) -> Result<(), NixideError> { + pub fn copy_closure_to(&self, dst_store: &Store, store_path: &StorePath) -> NixideResult<()> { wrap::nix_fn!(|ctx: &ErrorContext| unsafe { sys::nix_store_copy_closure( ctx.as_ptr(), self.as_ptr(), dst_store.as_ptr(), store_path.as_ptr(), - ); // semi-colon to return () and not i32 + ); }) } - pub fn copy_closure_from( - &self, - src_store: &Store, - store_path: &StorePath, - ) -> Result<(), NixideError> { + pub fn copy_closure_from(&self, src_store: &Store, store_path: &StorePath) -> NixideResult<()> { wrap::nix_fn!(|ctx: &ErrorContext| unsafe { sys::nix_store_copy_closure( ctx.as_ptr(), src_store.as_ptr(), self.as_ptr(), - store_path.inner.as_ptr(), + store_path.as_ptr(), ); - }) // semi-colon to return () and not i32 + }) } } @@ -246,7 +252,3 @@ impl Drop for Store { } } } - -// SAFETY: Store can be shared between threads -unsafe impl Send for Store {} -unsafe impl Sync for Store {} diff --git a/nixide/src/store/path.rs b/nixide/src/store/path.rs index d037c0e..40c139b 100644 --- a/nixide/src/store/path.rs +++ b/nixide/src/store/path.rs @@ -1,14 +1,14 @@ -use std::ffi::{c_void, CString}; +use std::ffi::{CString, c_void}; use std::path::PathBuf; use std::ptr::NonNull; use super::Store; -use crate::errors::{new_nixide_error, ErrorContext}; +use crate::NixideResult; +use crate::errors::{ErrorContext, new_nixide_error}; use crate::sys; use crate::util::panic_issue_call_failed; use crate::util::wrap; use crate::util::wrappers::AsInnerPtr; -use crate::NixideResult; /// A path in the Nix store. /// @@ -18,6 +18,25 @@ pub struct StorePath { pub(crate) inner: NonNull, } +impl Clone for StorePath { + fn clone(&self) -> Self { + let inner = wrap::nix_ptr_fn!(|_| unsafe { sys::nix_store_path_clone(self.as_ptr()) }) + .unwrap_or_else(|_| { + panic_issue_call_failed!("nix_store_path_clone returned None for valid path") + }); + + StorePath { inner } + } +} + +impl Drop for StorePath { + fn drop(&mut self) { + unsafe { + sys::nix_store_path_free(self.as_ptr()); + } + } +} + impl AsInnerPtr for StorePath { #[inline] unsafe fn as_ptr(&self) -> *mut sys::StorePath { @@ -127,26 +146,3 @@ impl StorePath { .is_ok() } } - -impl Clone for StorePath { - fn clone(&self) -> Self { - let inner = wrap::nix_ptr_fn!(|_| unsafe { sys::nix_store_path_clone(self.as_ptr()) }) - .unwrap_or_else(|_| { - panic_issue_call_failed!("nix_store_path_clone returned None for valid path") - }); - - StorePath { inner } - } -} - -impl Drop for StorePath { - fn drop(&mut self) { - unsafe { - sys::nix_store_path_free(self.as_ptr()); - } - } -} - -// SAFETY: StorePath can be shared between threads -unsafe impl Send for StorePath {} -unsafe impl Sync for StorePath {} diff --git a/nixide/src/store/tests.rs b/nixide/src/store/tests.rs index da72ae7..5943077 100644 --- a/nixide/src/store/tests.rs +++ b/nixide/src/store/tests.rs @@ -2,39 +2,24 @@ use serial_test::serial; use super::{Store, StorePath}; use crate::errors::ErrorContext; +use crate::init::LIBNIX_INIT_STATUS; use crate::sys; use crate::util::wrappers::AsInnerPtr as _; #[test] #[serial] fn test_store_opening() { - let mut ctx = ErrorContext::new(); - unsafe { - sys::nix_libutil_init(ctx.as_ptr()); - ctx.pop() - .expect("nix_libutil_init failed with bad ErrorContext"); - sys::nix_libstore_init(ctx.as_ptr()); - ctx.pop() - .expect("nix_libstore_init failed with bad ErrorContext"); - }; + assert!(unsafe { matches!(LIBNIX_INIT_STATUS, Some(Ok(_))) }); - let _store = Store::open(None).expect("Failed to open store"); + let _store = Store::default().expect("Failed to open store"); } #[test] #[serial] fn test_store_path_parse() { - let mut ctx = ErrorContext::new(); - unsafe { - sys::nix_libutil_init(ctx.as_ptr()); - ctx.pop() - .expect("nix_libutil_init failed with bad ErrorContext"); - sys::nix_libstore_init(ctx.as_ptr()); - ctx.pop() - .expect("nix_libstore_init failed with bad ErrorContext"); - }; + assert!(unsafe { matches!(LIBNIX_INIT_STATUS, Some(Ok(_))) }); - let store = Store::open(None).expect("Failed to open store"); + let store = Store::default().expect("Failed to open store"); // Try parsing a well-formed store path let result = StorePath::fake_path(&store); @@ -44,17 +29,9 @@ fn test_store_path_parse() { #[test] #[serial] fn test_store_path_clone() { - let mut ctx = ErrorContext::new(); - unsafe { - sys::nix_libutil_init(ctx.as_ptr()); - ctx.pop() - .expect("nix_libutil_init failed with bad ErrorContext"); - sys::nix_libstore_init(ctx.as_ptr()); - ctx.pop() - .expect("nix_libstore_init failed with bad ErrorContext"); - }; + assert!(unsafe { matches!(LIBNIX_INIT_STATUS, Some(Ok(_))) }); - let store = Store::open(None).expect("Failed to open store"); + let store = Store::default().expect("Failed to open store"); // Try to get a valid store path by parsing let path = StorePath::fake_path(&store).expect("Failed to create `StorePath::fake_path`");