diff --git a/Cargo.lock b/Cargo.lock index 154a81f..eec43ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,12 +11,6 @@ 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" @@ -124,40 +118,12 @@ 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" @@ -193,64 +159,12 @@ 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" @@ -260,18 +174,6 @@ 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" @@ -288,12 +190,6 @@ 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" @@ -330,7 +226,6 @@ dependencies = [ "nixide-sys", "serial_test", "stdext", - "tempfile", ] [[package]] @@ -395,16 +290,6 @@ 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" @@ -423,12 +308,6 @@ 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" @@ -473,19 +352,6 @@ 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" @@ -507,54 +373,6 @@ 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" @@ -616,194 +434,20 @@ 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 345f42f..3832ebc 100644 --- a/nixide/Cargo.toml +++ b/nixide/Cargo.toml @@ -23,7 +23,6 @@ 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 786daec..2ab2227 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,19 +67,6 @@ 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 { @@ -196,6 +183,7 @@ 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; @@ -230,9 +218,11 @@ impl ErrorContext { /// This function **never fails**. /// fn get_err(&self) -> Option { - match unsafe { sys::nix_err_code(self.as_ptr()) } { + let err = unsafe { sys::nix_err_code(self.as_ptr()) }; + + match err { sys::nix_err_NIX_OK => None, - err => Some(err), + _ => Some(err), } } @@ -267,17 +257,13 @@ impl ErrorContext { /// and avoid passing in a [sys::nix_c_context] struct. /// fn get_msg(&self) -> Option { - // 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 { + let ctx = ErrorContext::new(); + unsafe { + // NOTE: an Err here only occurs when `self.get_code() == Ok(())` + let mut n: c_uint = 0; 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, } } @@ -319,18 +305,19 @@ impl ErrorContext { /// ``` /// fn get_nix_err_name(&self) -> Option { - // 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 { + #[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| { 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. @@ -371,16 +358,19 @@ impl ErrorContext { /// ``` /// fn get_nix_err_info_msg(&self) -> Option { - // 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() + #[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() + } } } diff --git a/nixide/src/expr/eval_state.rs b/nixide/src/expr/eval_state.rs index c491642..3818d1a 100644 --- a/nixide/src/expr/eval_state.rs +++ b/nixide/src/expr/eval_state.rs @@ -1,5 +1,8 @@ -use std::ffi::{CString, c_void}; +use std::cell::RefCell; +use std::ffi::CString; use std::ptr::NonNull; +use std::rc::Rc; +use std::sync::Arc; use crate::errors::new_nixide_error; @@ -15,56 +18,46 @@ use crate::{NixideResult, Store}; /// This provides the main interface for evaluating Nix expressions /// and creating values. pub struct EvalState { - inner: NonNull, + inner: Rc>>, - store: Store, + // XXX: TODO: is an `Arc` necessary or just a `Store` + store: Arc, } -// 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.as_ptr() + self.inner.borrow().as_ptr() } #[inline] unsafe fn as_ref(&self) -> &sys::EvalState { - unsafe { self.inner.as_ref() } + unsafe { self.inner.borrow().as_ref() } } #[inline] unsafe fn as_mut(&mut self) -> &mut sys::EvalState { - unsafe { self.inner.as_mut() } + unsafe { self.inner.borrow_mut().as_mut() } } } impl EvalState { /// Construct a new EvalState directly from its attributes - /// - pub(super) fn new(inner: NonNull, store: &Store) -> Self { + pub(super) fn new(inner: NonNull, store: Arc) -> Self { Self { - inner, - store: store.clone(), + inner: Rc::new(RefCell::new(inner)), + store, } } - pub fn store_ref(&self) -> &Store { - &self.store + #[inline] + pub(crate) fn inner_ref(&self) -> Rc>> { + self.inner.clone() + } + + #[inline] + pub(crate) unsafe fn store_ref(&self) -> &Store { + self.store.as_ref() } /// Evaluate a Nix expression from a string. @@ -77,7 +70,7 @@ impl EvalState { /// # Errors /// /// Returns an error if evaluation fails. - pub fn interpret(&self, expr: &str, path: &str) -> NixideResult { + pub fn eval_from_string(&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)))?; @@ -99,7 +92,7 @@ impl EvalState { ); value }) - .map(|ptr| Value::from((ptr, self))) + .map(|ptr| Value::from((ptr, self.inner_ref()))) } } diff --git a/nixide/src/expr/eval_state_builder.rs b/nixide/src/expr/eval_state_builder.rs index ee3faeb..de2672b 100644 --- a/nixide/src/expr/eval_state_builder.rs +++ b/nixide/src/expr/eval_state_builder.rs @@ -1,5 +1,6 @@ -use std::ffi::{CString, c_char, c_void}; +use std::ffi::{CString, c_char}; use std::ptr::{self, NonNull}; +use std::sync::Arc; use super::EvalState; #[cfg(feature = "flakes")] @@ -14,28 +15,11 @@ 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: Store, + store: Arc, } -// 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 { @@ -63,15 +47,17 @@ impl EvalStateBuilder { /// # Errors /// /// Returns an error if the builder cannot be created. - /// - pub fn new(store: &Store) -> NixideResult { + pub fn new(store: &Arc) -> 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: store.clone(), + store: Arc::clone(store), }) } @@ -80,20 +66,18 @@ 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)) + Ok(EvalState::new(inner, self.store.clone())) } - // XXX: TODO: use `flakes()` instead - #[deprecated] + // XXX: TODO #[cfg(feature = "flakes")] - pub fn set_flake_settings(self, settings: &FlakeSettings) -> NixideResult { + 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(), @@ -105,13 +89,7 @@ impl EvalStateBuilder { Ok(self) } - #[cfg(feature = "flakes")] - pub fn flakes(self) -> NixideResult { - #[allow(deprecated)] - self.set_flake_settings(&FlakeSettings::new()?) - } - - pub fn load_ambient_settings(self) -> NixideResult { + fn load_ambient_settings(self) -> NixideResult { wrap::nix_fn!(|ctx: &ErrorContext| unsafe { sys::nix_eval_state_builder_load(ctx.as_ptr(), self.as_ptr()); })?; @@ -119,7 +97,7 @@ impl EvalStateBuilder { Ok(self) } - pub fn set_lookup_path>(self, paths: Vec

) -> NixideResult { + 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 5d5e08f..acae8c1 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, c_void}; +use std::ffi::c_char; use std::ptr::NonNull; use crate::errors::ErrorContext; use crate::expr::values::NixString; use crate::stdext::CCharPtrExt; use crate::sys; -use crate::util::LazyArray; use crate::util::wrappers::AsInnerPtr; +use crate::util::LazyArray; use crate::util::{panic_issue_call_failed, wrap}; use crate::{EvalState, NixideResult, StorePath}; @@ -17,23 +17,6 @@ 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 { @@ -98,7 +81,7 @@ impl<'a> RealisedString<'a> { path: Self::parse_path(inner.as_ptr(), state), children: LazyArray::new( size, - Box::new(|_| StorePath::fake_path(state.store_ref()).unwrap()), + Box::new(|_| StorePath::fake_path(unsafe { state.store_ref() }).unwrap()), ), }) } @@ -115,7 +98,7 @@ impl<'a> RealisedString<'a> { err ) }); - StorePath::parse(state.store_ref(), &path_str).unwrap_or_else(|err| { + StorePath::parse(unsafe { 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 5233ea2..0b32729 100644 --- a/nixide/src/expr/tests.rs +++ b/nixide/src/expr/tests.rs @@ -1,4 +1,4 @@ -use std::rc::Rc; +use std::sync::Arc; use serial_test::serial; @@ -8,7 +8,7 @@ use crate::Store; #[test] #[serial] fn test_eval_state_builder() { - let store = Rc::new(Store::default().expect("Failed to open store")); + let store = Arc::new(Store::open(None).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 = Rc::new(Store::default().expect("Failed to open store")); + let store = Arc::new(Store::open(None).expect("Failed to open store")); let state = EvalStateBuilder::new(&store) .expect("Failed to create builder") .build() .expect("Failed to build state"); let result = state - .interpret("1 + 2", "") + .eval_from_string("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 = Store::default().expect("Failed to open store"); + let store = Arc::new(Store::open(None).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 - .interpret("42", "") + .eval_from_string("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 - .interpret("true", "") + .eval_from_string("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 - .interpret("\"hello\"", "") + .eval_from_string("\"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 = Store::default().expect("Failed to open store"); + let store = Arc::new(Store::open(None).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 - .interpret("42", "") + .eval_from_string("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 - .interpret("true", "") + .eval_from_string("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 - .interpret("false", "") + .eval_from_string("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 - .interpret("\"hello world\"", "") + .eval_from_string("\"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 - .interpret("\"say \\\"hello\\\"\"", "") + .eval_from_string("\"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 - .interpret("null", "") + .eval_from_string("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 - .interpret("{ a = 1; }", "") + .eval_from_string("{ 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 - .interpret("[ 1 2 3 ]", "") + .eval_from_string("[ 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 9f8f8e4..4baacd0 100644 --- a/nixide/src/expr/values/attrs.rs +++ b/nixide/src/expr/values/attrs.rs @@ -1,37 +1,22 @@ +use std::cell::RefCell; 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: EvalState, + state: Rc>>, len: u32, } -impl Clone for NixAttrs { - fn clone(&self) -> Self { - let inner = self.inner.clone(); - - wrap::nix_fn!(|ctx: &ErrorContext| unsafe { - sys::nix_value_incref(ctx.as_ptr(), self.as_ptr()); - }) - .unwrap(); - - Self { - inner, - state: self.state.clone(), - len: self.len, - } - } -} - impl Drop for NixAttrs { fn drop(&mut self) { let ctx = ErrorContext::new(); @@ -76,17 +61,13 @@ impl NixValue for NixAttrs { sys::ValueType_NIX_TYPE_ATTRS } - fn from(inner: NonNull, state: &EvalState) -> Self { + fn from(inner: NonNull, state: Rc>>) -> 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: state.clone(), - len, - } + Self { inner, state, len } } } @@ -107,7 +88,7 @@ impl NixAttrs { sys::nix_get_attr_byidx( ctx.as_ptr(), self.as_ptr(), - self.state.as_ptr(), + self.state.borrow_mut().as_ptr(), index, name_ptr, ) @@ -118,7 +99,7 @@ impl NixAttrs { .to_utf8_string() .unwrap_or_else(|err| panic_issue_call_failed!("{}", err)); - let value = Value::from((inner, &self.state)); + let value = Value::from((inner, self.state.clone())); Some((name, value)) } @@ -134,7 +115,7 @@ impl NixAttrs { sys::nix_get_attr_byidx_lazy( ctx.as_ptr(), self.as_ptr(), - self.state.as_ptr(), + self.state.borrow_mut().as_ptr(), index, name_ptr, ) @@ -145,7 +126,7 @@ impl NixAttrs { .to_utf8_string() .unwrap_or_else(|err| panic_issue_call_failed!("{}", err)); - let value = ::from(inner, &self.state); + let value = ::from(inner, self.state.clone()); Some((name, value)) } @@ -156,7 +137,12 @@ 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.as_ptr(), index) + sys::nix_get_attr_name_byidx( + ctx.as_ptr(), + self.as_ptr(), + self.state.borrow_mut().as_ptr(), + index, + ) }) .unwrap_or_else(|err| panic_issue_call_failed!("{}", err)); @@ -175,7 +161,7 @@ impl NixAttrs { sys::nix_get_attr_byname( ctx.as_ptr(), self.as_ptr(), - self.state.as_ptr(), + self.state.borrow_mut().as_ptr(), name.as_ref() .into_c_ptr() .unwrap_or_else(|err| panic_issue_call_failed!("{}", err)), @@ -183,7 +169,7 @@ impl NixAttrs { }); match result { - Ok(inner) => Some(Value::from((inner, &self.state))), + Ok(inner) => Some(Value::from((inner, self.state.clone()))), Err(NixideError::NixError { err: NixError::KeyNotFound(_), @@ -201,7 +187,7 @@ impl NixAttrs { sys::nix_get_attr_byname_lazy( ctx.as_ptr(), self.as_ptr(), - self.state.as_ptr(), + self.state.borrow_mut().as_ptr(), name.as_ref() .into_c_ptr() .unwrap_or_else(|err| panic_issue_call_failed!("{}", err)), @@ -209,7 +195,7 @@ impl NixAttrs { }); match result { - Ok(inner) => Some(::from(inner, &self.state)), + Ok(inner) => Some(::from(inner, self.state.clone())), Err(NixideError::NixError { err: NixError::KeyNotFound(_), diff --git a/nixide/src/expr/values/bool.rs b/nixide/src/expr/values/bool.rs index dd04031..01f5718 100644 --- a/nixide/src/expr/values/bool.rs +++ b/nixide/src/expr/values/bool.rs @@ -1,36 +1,21 @@ +use std::cell::RefCell; 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: EvalState, + state: Rc>>, value: bool, } -impl Clone for NixBool { - fn clone(&self) -> Self { - let inner = self.inner.clone(); - - wrap::nix_fn!(|ctx: &ErrorContext| unsafe { - sys::nix_value_incref(ctx.as_ptr(), self.as_ptr()); - }) - .unwrap(); - - Self { - inner, - state: self.state.clone(), - value: self.value, - } - } -} - impl Drop for NixBool { fn drop(&mut self) { let ctx = ErrorContext::new(); @@ -75,7 +60,7 @@ impl NixValue for NixBool { sys::ValueType_NIX_TYPE_BOOL } - fn from(inner: NonNull, state: &EvalState) -> Self { + fn from(inner: NonNull, state: Rc>>) -> Self { let value = wrap::nix_fn!(|ctx: &ErrorContext| unsafe { sys::nix_get_bool(ctx.as_ptr(), inner.as_ptr()) }) @@ -85,7 +70,7 @@ impl NixValue for NixBool { Self { inner, - state: state.clone(), + state, value, } } diff --git a/nixide/src/expr/values/float.rs b/nixide/src/expr/values/float.rs index 9538b45..b47569b 100644 --- a/nixide/src/expr/values/float.rs +++ b/nixide/src/expr/values/float.rs @@ -1,8 +1,9 @@ +use std::cell::RefCell; 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; @@ -10,27 +11,10 @@ use crate::util::{panic_issue_call_failed, wrap}; pub struct NixFloat { inner: NonNull, - state: EvalState, + state: Rc>>, value: f64, } -impl Clone for NixFloat { - fn clone(&self) -> Self { - let inner = self.inner.clone(); - - wrap::nix_fn!(|ctx: &ErrorContext| unsafe { - sys::nix_value_incref(ctx.as_ptr(), self.as_ptr()); - }) - .unwrap(); - - Self { - inner, - state: self.state.clone(), - value: self.value, - } - } -} - impl Drop for NixFloat { fn drop(&mut self) { let ctx = ErrorContext::new(); @@ -75,7 +59,7 @@ impl NixValue for NixFloat { sys::ValueType_NIX_TYPE_FLOAT } - fn from(inner: NonNull, state: &EvalState) -> Self { + fn from(inner: NonNull, state: Rc>>) -> Self { let value = wrap::nix_fn!(|ctx: &ErrorContext| unsafe { sys::nix_get_float(ctx.as_ptr(), inner.as_ptr()) }) @@ -85,7 +69,7 @@ impl NixValue for NixFloat { Self { inner, - state: state.clone(), + state, value, } } diff --git a/nixide/src/expr/values/function.rs b/nixide/src/expr/values/function.rs index 83d7d2a..98827b1 100644 --- a/nixide/src/expr/values/function.rs +++ b/nixide/src/expr/values/function.rs @@ -1,32 +1,19 @@ +use std::cell::RefCell; 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: EvalState, -} - -impl Clone for NixFunction { - fn clone(&self) -> Self { - let inner = self.inner.clone(); - - wrap::nix_fn!(|ctx: &ErrorContext| unsafe { - sys::nix_value_incref(ctx.as_ptr(), self.as_ptr()); - }) - .unwrap(); - - Self { - inner, - state: self.state.clone(), - } - } + state: Rc>>, + value: i64, } impl Drop for NixFunction { @@ -73,10 +60,16 @@ impl NixValue for NixFunction { sys::ValueType_NIX_TYPE_FUNCTION } - fn from(inner: NonNull, state: &EvalState) -> Self { + 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)); + Self { inner, - state: state.clone(), + state, + value, } } } @@ -87,14 +80,14 @@ impl NixFunction { T: NixValue, { let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe { - sys::nix_alloc_value(ctx.as_ptr(), self.state.as_ptr()) + sys::nix_alloc_value(ctx.as_ptr(), self.state.borrow().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.as_ptr(), + self.state.borrow().as_ptr(), self.as_ptr(), arg.as_ptr(), inner.as_ptr(), @@ -102,7 +95,7 @@ impl NixFunction { }) .unwrap_or_else(|err| panic_issue_call_failed!("{}", err)); - Value::from((inner, &self.state)) + Value::from((inner, self.state.clone())) } pub fn call_many(&self, args: &[&T]) -> Value @@ -110,14 +103,14 @@ impl NixFunction { T: NixValue, { let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe { - sys::nix_alloc_value(ctx.as_ptr(), self.state.as_ptr()) + sys::nix_alloc_value(ctx.as_ptr(), self.state.borrow().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.as_ptr(), + self.state.borrow().as_ptr(), self.as_ptr(), args.len(), args.into_c_array(), @@ -126,7 +119,7 @@ impl NixFunction { }) .unwrap_or_else(|err| panic_issue_call_failed!("{}", err)); - Value::from((inner, &self.state)) + Value::from((inner, self.state.clone())) } } diff --git a/nixide/src/expr/values/int.rs b/nixide/src/expr/values/int.rs index 86e5e94..4ddd147 100644 --- a/nixide/src/expr/values/int.rs +++ b/nixide/src/expr/values/int.rs @@ -1,8 +1,9 @@ +use std::cell::RefCell; 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; @@ -10,27 +11,10 @@ use crate::util::{panic_issue_call_failed, wrap}; pub struct NixInt { inner: NonNull, - state: EvalState, + state: Rc>>, value: i64, } -impl Clone for NixInt { - fn clone(&self) -> Self { - let inner = self.inner.clone(); - - wrap::nix_fn!(|ctx: &ErrorContext| unsafe { - sys::nix_value_incref(ctx.as_ptr(), self.as_ptr()); - }) - .unwrap(); - - Self { - inner, - state: self.state.clone(), - value: self.value, - } - } -} - impl Drop for NixInt { fn drop(&mut self) { let ctx = ErrorContext::new(); @@ -75,7 +59,7 @@ impl NixValue for NixInt { sys::ValueType_NIX_TYPE_INT } - fn from(inner: NonNull, state: &EvalState) -> Self { + 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()) }) @@ -83,7 +67,7 @@ impl NixValue for NixInt { Self { inner, - state: state.clone(), + state, value, } } diff --git a/nixide/src/expr/values/list.rs b/nixide/src/expr/values/list.rs index 4c0f354..fb82bc7 100644 --- a/nixide/src/expr/values/list.rs +++ b/nixide/src/expr/values/list.rs @@ -1,8 +1,9 @@ +use std::cell::RefCell; 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; @@ -10,23 +11,7 @@ use crate::util::{panic_issue_call_failed, wrap}; pub struct NixList { inner: NonNull, - state: EvalState, -} - -impl Clone for NixList { - fn clone(&self) -> Self { - let inner = self.inner.clone(); - - wrap::nix_fn!(|ctx: &ErrorContext| unsafe { - sys::nix_value_incref(ctx.as_ptr(), self.as_ptr()); - }) - .unwrap(); - - Self { - inner, - state: self.state.clone(), - } - } + state: Rc>>, } impl Drop for NixList { @@ -73,11 +58,8 @@ impl NixValue for NixList { sys::ValueType_NIX_TYPE_LIST } - fn from(inner: NonNull, state: &EvalState) -> Self { - Self { - inner, - state: state.clone(), - } + fn from(inner: NonNull, state: Rc>>) -> Self { + Self { inner, state } } } @@ -116,19 +98,29 @@ 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.as_ptr(), index) + sys::nix_get_list_byidx( + ctx.as_ptr(), + self.as_ptr(), + self.state.borrow().as_ptr(), + index, + ) }) .unwrap_or_else(|err| panic_issue_call_failed!("{}", err)); - Value::from((inner, &self.state)) + Value::from((inner, self.state.clone())) } 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.as_ptr(), index) + sys::nix_get_list_byidx_lazy( + ctx.as_ptr(), + self.as_ptr(), + self.state.borrow().as_ptr(), + index, + ) }) .unwrap_or_else(|err| panic_issue_call_failed!("{}", err)); - ::from(inner, &self.state) + ::from(inner, self.state.clone()) } } diff --git a/nixide/src/expr/values/mod.rs b/nixide/src/expr/values/mod.rs index f6f6b80..6b1f459 100644 --- a/nixide/src/expr/values/mod.rs +++ b/nixide/src/expr/values/mod.rs @@ -23,8 +23,10 @@ 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; @@ -38,12 +40,12 @@ use crate::sys::{ use crate::util::wrappers::AsInnerPtr; use crate::util::{panic_issue_call_failed, wrap}; -pub trait NixValue: Clone + Drop + Display + Debug + AsInnerPtr { +pub trait NixValue: Drop + Display + Debug + AsInnerPtr { /// TODO fn type_id(&self) -> sys::ValueType; /// TODO - fn from(inner: NonNull, state: &EvalState) -> Self; + fn from(inner: NonNull, state: Rc>>) -> Self; } /// A Nix value @@ -109,12 +111,22 @@ pub enum Value { // Failed(NixFailed), } -impl From<(NonNull, &EvalState)> for Value { - fn from(value: (NonNull, &EvalState)) -> Self { +impl + From<( + NonNull, + Rc>>, + )> for Value +{ + fn from( + value: ( + NonNull, + Rc>>, + ), + ) -> Self { let (inner, state) = value; wrap::nix_fn!(|ctx: &ErrorContext| unsafe { - sys::nix_value_force(ctx.as_ptr(), state.as_ptr(), inner.as_ptr()) + sys::nix_value_force(ctx.as_ptr(), state.borrow().as_ptr(), inner.as_ptr()) }) .unwrap_or_else(|err| panic_issue_call_failed!("{}", err)); @@ -185,3 +197,13 @@ 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 fd20445..11440de 100644 --- a/nixide/src/expr/values/null.rs +++ b/nixide/src/expr/values/null.rs @@ -1,32 +1,16 @@ +use std::cell::RefCell; 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: EvalState, -} - -impl Clone for NixNull { - fn clone(&self) -> Self { - let inner = self.inner.clone(); - - wrap::nix_fn!(|ctx: &ErrorContext| unsafe { - sys::nix_value_incref(ctx.as_ptr(), self.as_ptr()); - }) - .unwrap(); - - Self { - inner, - state: self.state.clone(), - } - } + state: Rc>>, } impl Drop for NixNull { @@ -73,10 +57,7 @@ impl NixValue for NixNull { sys::ValueType_NIX_TYPE_NULL } - fn from(inner: NonNull, state: &EvalState) -> Self { - Self { - inner, - state: state.clone(), - } + fn from(inner: NonNull, state: Rc>>) -> Self { + Self { inner, state } } } diff --git a/nixide/src/expr/values/path.rs b/nixide/src/expr/values/path.rs index 6d51fd6..b25dfa6 100644 --- a/nixide/src/expr/values/path.rs +++ b/nixide/src/expr/values/path.rs @@ -1,38 +1,23 @@ +use std::cell::RefCell; 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: EvalState, + state: Rc>>, value: PathBuf, } -impl Clone for NixPath { - fn clone(&self) -> Self { - let inner = self.inner.clone(); - - wrap::nix_fn!(|ctx: &ErrorContext| unsafe { - sys::nix_value_incref(ctx.as_ptr(), self.as_ptr()); - }) - .unwrap(); - - Self { - inner, - state: self.state.clone(), - value: self.value.clone(), - } - } -} - impl Drop for NixPath { fn drop(&mut self) { let ctx = ErrorContext::new(); @@ -77,7 +62,7 @@ impl NixValue for NixPath { sys::ValueType_NIX_TYPE_PATH } - fn from(inner: NonNull, state: &EvalState) -> Self { + fn from(inner: NonNull, state: Rc>>) -> Self { let value = wrap::nix_fn!(|ctx: &ErrorContext| unsafe { sys::nix_get_path_string(ctx.as_ptr(), inner.as_ptr()) }) @@ -87,7 +72,7 @@ impl NixValue for NixPath { Self { inner, - state: state.clone(), + state, value, } } diff --git a/nixide/src/expr/values/string.rs b/nixide/src/expr/values/string.rs index 765d763..93ec66d 100644 --- a/nixide/src/expr/values/string.rs +++ b/nixide/src/expr/values/string.rs @@ -1,36 +1,22 @@ +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: EvalState, + state: Rc>>, value: String, } -impl Clone for NixString { - fn clone(&self) -> Self { - let inner = self.inner.clone(); - - wrap::nix_fn!(|ctx: &ErrorContext| unsafe { - sys::nix_value_incref(ctx.as_ptr(), self.as_ptr()); - }) - .unwrap(); - - Self { - inner, - state: self.state.clone(), - value: self.value.clone(), - } - } -} - impl Drop for NixString { fn drop(&mut self) { let ctx = ErrorContext::new(); @@ -75,7 +61,7 @@ impl NixValue for NixString { sys::ValueType_NIX_TYPE_STRING } - fn from(inner: NonNull, state: &EvalState) -> Self { + fn from(inner: NonNull, state: Rc>>) -> Self { let value = wrap::nix_string_callback!( |callback, userdata: *mut __UserData, ctx: &ErrorContext| unsafe { sys::nix_get_string( @@ -90,7 +76,7 @@ impl NixValue for NixString { Self { inner, - state: state.clone(), + state, value, } } diff --git a/nixide/src/expr/values/thunk.rs b/nixide/src/expr/values/thunk.rs index b6439ce..6327623 100644 --- a/nixide/src/expr/values/thunk.rs +++ b/nixide/src/expr/values/thunk.rs @@ -1,8 +1,9 @@ +use std::cell::RefCell; 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; @@ -10,23 +11,7 @@ use crate::util::{panic_issue_call_failed, wrap}; pub struct NixThunk { inner: NonNull, - state: EvalState, -} - -impl Clone for NixThunk { - fn clone(&self) -> Self { - let inner = self.inner.clone(); - - wrap::nix_fn!(|ctx: &ErrorContext| unsafe { - sys::nix_value_incref(ctx.as_ptr(), self.as_ptr()); - }) - .unwrap(); - - Self { - inner, - state: self.state.clone(), - } - } + state: Rc>>, } impl Drop for NixThunk { @@ -73,21 +58,26 @@ impl NixValue for NixThunk { sys::ValueType_NIX_TYPE_THUNK } - fn from(inner: NonNull, state: &EvalState) -> Self { - Self { - inner, - state: state.clone(), - } + fn from(inner: NonNull, state: Rc>>) -> Self { + Self { inner, state } } } 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.as_ptr(), self.inner.as_ptr()) + sys::nix_value_force( + ctx.as_ptr(), + self.state.borrow().as_ptr(), + self.inner.as_ptr(), + ) }) .unwrap_or_else(|err| panic_issue_call_failed!("{}", err)); - Value::from((self.inner, &self.state)) + Value::from((self.inner, self.state.to_owned())) } } diff --git a/nixide/src/flake/eval_state_builder_ext.rs b/nixide/src/flake/eval_state_builder_ext.rs new file mode 100644 index 0000000..ff8598f --- /dev/null +++ b/nixide/src/flake/eval_state_builder_ext.rs @@ -0,0 +1,14 @@ +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 1f24d04..ac4f5ca 100644 --- a/nixide/src/flake/fetchers_settings.rs +++ b/nixide/src/flake/fetchers_settings.rs @@ -1,39 +1,28 @@ -use std::ffi::c_void; use std::ptr::NonNull; -use crate::NixideResult; -use crate::errors::ErrorContext; +use crate::errors::{new_nixide_error, ErrorContext}; use crate::sys; -use crate::util::wrap; use crate::util::wrappers::AsInnerPtr; +use crate::NixideError; -pub struct FetchersSettings { - inner: NonNull, +pub(super) struct FetchersSettings { + pub(super) ptr: NonNull, } impl FetchersSettings { - pub fn new() -> NixideResult { - let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe { - sys::nix_fetchers_settings_new(ctx.as_ptr()) - })?; + 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))?, + }) + } - Ok(Self { inner }) + pub(crate) unsafe fn as_ptr(&self) -> *mut sys::nix_fetchers_settings { + self.ptr.as_ptr() } } -// 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 { @@ -42,23 +31,6 @@ 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 8b3985a..bb066ec 100644 --- a/nixide/src/flake/flake_lock_flags.rs +++ b/nixide/src/flake/flake_lock_flags.rs @@ -1,26 +1,22 @@ -use std::ffi::c_void; +use std::ffi::CString; use std::ptr::NonNull; use super::{FlakeReference, FlakeSettings}; -use crate::NixideResult; +use crate::errors::new_nixide_error; 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, Copy)] +#[derive(Debug, Clone)] 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, } @@ -28,20 +24,6 @@ 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 { @@ -49,49 +31,69 @@ 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 }) + } -impl AsInnerPtr for FlakeLockFlags { - #[inline] - unsafe fn as_ptr(&self) -> *mut sys::nix_flake_lock_flags { + pub(crate) fn as_ptr(&self) -> *mut sys::nix_flake_lock_flags { self.inner.as_ptr() } - #[inline] - unsafe fn as_ref(&self) -> &sys::nix_flake_lock_flags { - unsafe { self.inner.as_ref() } + 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_mut(&mut self) -> &mut sys::nix_flake_lock_flags { - unsafe { self.inner.as_mut() } - } -} + /// 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", + // ) + // }) + // } -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()) - })?; + /// 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", + // ) + // }) + // } - 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()) - }, - }; - }) - } + /// 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", + // ) + // }) + // } /// Adds an input override to the lock file that will be produced. /// The [LockedFlake::lock] operation will not write to the lock file. @@ -104,17 +106,26 @@ impl FlakeLockFlags { /// # Arguments /// /// * `path` - The input name/path to override (must not be empty) - /// * `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()?; + /// * `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))); - wrap::nix_fn!(|ctx: &ErrorContext| unsafe { + let ctx = ErrorContext::new(); + unsafe { sys::nix_flake_lock_flags_add_input_override( ctx.as_ptr(), self.as_ptr(), - input_path, + input_path.as_ptr(), 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 67ddf41..c60a950 100644 --- a/nixide/src/flake/flake_reference.rs +++ b/nixide/src/flake/flake_reference.rs @@ -1,99 +1,58 @@ -use std::ffi::c_void; use std::os::raw::c_char; -use std::ptr::{NonNull, null_mut}; +use std::ptr::{null_mut, NonNull}; use super::{FetchersSettings, FlakeReferenceParseFlags, FlakeSettings}; -use crate::NixideError; -use crate::errors::{ErrorContext, new_nixide_error}; +use crate::errors::new_nixide_error; use crate::sys; -use crate::util::wrap; +use crate::util::bindings::wrap_nix_string_callback; use crate::util::wrappers::AsInnerPtr; +use crate::NixideError; -// XXX: TODO: rename FlakeReference -> FlakeRef pub struct FlakeReference { - inner: NonNull, - fragment: String, + pub(crate) ptr: NonNull, } -// 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.as_ptr()); + sys::nix_flake_reference_free(self.ptr.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( + pub fn parse_with_fragment( fetch_settings: &FetchersSettings, flake_settings: &FlakeSettings, flags: &FlakeReferenceParseFlags, reference: &str, - ) -> Result { + ) -> Result<(FlakeReference, String), NixideError> { let mut ptr: *mut sys::nix_flake_reference = null_mut(); - let fragment = wrap::nix_string_callback!( - |callback, userdata: *mut __UserData, ctx: &ErrorContext| unsafe { - sys::nix_flake_reference_and_fragment_from_string( - ctx.as_ptr(), - fetch_settings.as_ptr(), - flake_settings.as_ptr(), - flags.as_ptr(), - reference.as_ptr() as *const c_char, - reference.len(), - &mut ptr, - Some(callback), - userdata as *mut c_void, - ) - } - )?; + 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, + ) + }); match NonNull::new(ptr) { - Some(inner) => Ok(FlakeReference { inner, fragment }), + Some(ptr) => result.map(|s| (FlakeReference { ptr }, s)), 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 cddf391..39bbf78 100644 --- a/nixide/src/flake/flake_reference_parse_flags.rs +++ b/nixide/src/flake/flake_reference_parse_flags.rs @@ -1,77 +1,58 @@ -use std::ffi::c_void; use std::os::raw::c_char; use std::ptr::NonNull; use super::FlakeSettings; -use crate::NixideResult; -use crate::errors::ErrorContext; +use crate::errors::{new_nixide_error, 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 { - inner: NonNull, + pub(crate) ptr: 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.inner.as_ptr()); + sys::nix_flake_reference_parse_flags_free(self.ptr.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) -> 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 }) + 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 }) + }), + } } /// 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) -> NixideResult<()> { - wrap::nix_fn!(|ctx: &ErrorContext| unsafe { + pub fn set_base_directory(&mut self, base_directory: &str) -> Result<(), NixideError> { + let ctx = ErrorContext::new(); + 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 295115b..3ef46da 100644 --- a/nixide/src/flake/flake_settings.rs +++ b/nixide/src/flake/flake_settings.rs @@ -1,15 +1,52 @@ -use std::ffi::c_void; use std::ptr::NonNull; -use crate::NixideResult; -use crate::errors::ErrorContext; +use crate::errors::{ErrorContext, new_nixide_error}; 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 { - inner: NonNull, + 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(()), + } + } } impl Drop for FlakeSettings { @@ -19,43 +56,3 @@ 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 a2ae9af..f11732c 100644 --- a/nixide/src/flake/locked_flake.rs +++ b/nixide/src/flake/locked_flake.rs @@ -1,184 +1,145 @@ -// 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::ErrorContext; +use crate::errors::{new_nixide_error, ErrorContext}; use crate::sys; -use crate::util::wrap; use crate::util::wrappers::AsInnerPtr; -use crate::{EvalState, NixideResult, Value}; +use crate::{EvalState, NixideError, Value}; pub struct LockedFlake { - inner: NonNull, - - flakeref: FlakeReference, - state: EvalState, - flags: FlakeLockFlags, - fetch_settings: FetchersSettings, - flake_settings: FlakeSettings, + pub(crate) ptr: NonNull, } - -// 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.as_ptr()); + sys::nix_locked_flake_free(self.ptr.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, - state: &EvalState, + eval_state: &EvalState, flags: &FlakeLockFlags, - flakeref: &FlakeReference, - ) -> NixideResult { - let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe { + flake_ref: &FlakeReference, + ) -> Result { + let ctx = ErrorContext::new(); + + let ptr = NonNull::new(unsafe { sys::nix_flake_lock( ctx.as_ptr(), fetch_settings.as_ptr(), flake_settings.as_ptr(), - state.as_ptr(), + eval_state.as_ptr(), flags.as_ptr(), - flakeref.as_ptr(), + flake_ref.as_ptr(), ) - })?; + }); - Ok(Self { - inner, - flakeref: flakeref.clone(), - state: state.clone(), - flags: flags.clone(), - fetch_settings: fetch_settings.clone(), - flake_settings: flake_settings.clone(), - }) + match ptr { + Some(ptr) => Ok(LockedFlake { ptr }), + None => Err(new_nixide_error!(NullPtr)), + } } /// Returns the outputs of the flake - the result of calling the `outputs` attribute. - pub fn outputs(&self) -> NixideResult { - let value = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe { + pub fn outputs( + &self, + flake_settings: &FlakeSettings, + eval_state: &mut EvalState, + ) -> Result { + let ctx = ErrorContext::new(); + + let r = unsafe { sys::nix_locked_flake_get_output_attrs( ctx.as_ptr(), - self.flake_settings.as_ptr(), - self.state.as_ptr(), - self.inner.as_ptr(), + flake_settings.as_ptr(), + eval_state.as_ptr(), + self.ptr.as_ptr(), ) - })?; - - Ok(Value::from((value, &self.state))) + }; + Ok(nix_bindings_expr::value::__private::raw_value_new(r)) } } #[cfg(test)] mod tests { - use std::fs; - use std::sync::Once; + // use nix_bindings_expr::eval_state::{gc_register_my_thread, EvalStateBuilder}; - use super::{FetchersSettings, FlakeLockFlags, FlakeReference, FlakeSettings, LockedFlake}; use crate::flake::{FlakeLockMode, FlakeReferenceParseFlags}; - use crate::{EvalStateBuilder, Store, Value, set_global_setting}; + use crate::{EvalStateBuilder, Store}; + + use super::*; + use std::sync::Once; 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(|| unsafe { - set_global_setting("experimental-features", "flakes").unwrap(); + INIT.call_once(|| { + nix_bindings_expr::eval_state::init().unwrap(); + nix_bindings_util::settings::set("experimental-features", "flakes").unwrap(); }); } #[test] fn flake_settings_getflake_exists() { init(); - - let store = Store::default().expect("Failed to open store connection"); - let state = EvalStateBuilder::new(&store) + let gc_registration = gc_register_my_thread(); + let store = Store::open(None, []).unwrap(); + let mut eval_state = EvalStateBuilder::new(store) .unwrap() - .flakes() + .flakes(&FlakeSettings::new().unwrap()) .unwrap() .build() .unwrap(); - let value = state.interpret("builtins?getFlake", "").unwrap(); + let v = eval_state + .eval_from_string("builtins?getFlake", "") + .unwrap(); - assert!(matches!(value, Value::Bool(_))); - if let Value::Bool(v) = value { - assert!(v.as_bool()); - } + let b = eval_state.require_bool(&v).unwrap(); + + assert!(b); + + drop(gc_registration); } #[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"); - fs::write( + std::fs::write( &flake_nix, r#" { outputs = { ... }: { - hello = "world"; + hello = "potato"; }; } "#, ) .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 flakeref = FlakeReference::parse( + let (flake_ref, fragment) = FlakeReference::parse_with_fragment( &fetchers_settings, &flake_settings, &FlakeReferenceParseFlags::new(&flake_settings).unwrap(), @@ -186,40 +147,41 @@ mod tests { ) .unwrap(); - assert_eq!(flakeref.fragment(), "subthing"); + assert_eq!(fragment, "subthing"); let locked_flake = LockedFlake::lock( &fetchers_settings, &flake_settings, &eval_state, &flake_lock_flags, - &flakeref, + &flake_ref, ) .unwrap(); - let outputs = locked_flake.outputs().unwrap(); + let outputs = locked_flake + .outputs(&flake_settings, &mut eval_state) + .unwrap(); - assert!(matches!(outputs, Value::Attrs(_))); - if let Value::Attrs(outputs) = outputs { - let value = outputs.get("hello").unwrap(); + let hello = eval_state.require_attrs_select(&outputs, "hello").unwrap(); + let hello = eval_state.require_string(&hello).unwrap(); - assert!(matches!(value, Value::String(_))); - if let Value::String(value) = value { - assert_eq!(value.as_string(), "world"); - } - } + assert_eq!(hello, "potato"); + + drop(fetchers_settings); + drop(tmp_dir); + drop(gc_registration); } #[test] fn flake_lock_load_flake_with_flags() { init(); - - let store = Store::default().unwrap(); + 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) + let mut eval_state = EvalStateBuilder::new(store) .unwrap() - .set_flake_settings(&flake_settings) + .flakes(&flake_settings) .unwrap() .build() .unwrap(); @@ -260,7 +222,7 @@ mod tests { r#" { outputs = { ... }: { - hello = "ALICE"; + hello = "BOB"; }; } "#, @@ -289,7 +251,7 @@ mod tests { .set_base_directory(tmp_dir.path().to_str().unwrap()) .unwrap(); - let flakeref_a = FlakeReference::parse( + let (flake_ref_a, fragment) = FlakeReference::parse_with_fragment( &fetchers_settings, &flake_settings, &flake_reference_parse_flags, @@ -297,17 +259,20 @@ mod tests { ) .unwrap(); - assert_eq!(flakeref_a.fragment(), ""); + assert_eq!(fragment, ""); // Step 1: Do not update (check), fails - flake_lock_flags.set_mode(&FlakeLockMode::Check).unwrap(); + + flake_lock_flags + .set_lock_mode(&FlakeLockMode::Check) + .unwrap(); let locked_flake = LockedFlake::lock( &fetchers_settings, &flake_settings, &eval_state, &flake_lock_flags, - &flakeref_a, + &flake_ref_a, ); // Has not been locked and would need to write a lock file. assert!(locked_flake.is_err()); @@ -317,50 +282,8 @@ mod tests { }; // Step 2: Update but do not write, succeeds - flake_lock_flags.set_mode(&FlakeLockMode::Virtual).unwrap(); - - let locked_flake = LockedFlake::lock( - &fetchers_settings, - &flake_settings, - &eval_state, - &flake_lock_flags, - &flakeref_a, - ) - .unwrap(); - - let outputs = locked_flake.outputs().unwrap(); - - assert!(matches!(outputs, Value::Attrs(_))); - if let Value::Attrs(outputs) = outputs { - let value = outputs.get("hello").unwrap(); - - assert!(matches!(value, Value::String(_))); - if let Value::String(value) = value { - assert_eq!(value.as_string(), "ALICE"); - } - } - - // Step 3: The lock was not written, so Step 1 would fail again - flake_lock_flags.set_mode(&FlakeLockMode::Check).unwrap(); - - let locked_flake = LockedFlake::lock( - &fetchers_settings, - &flake_settings, - &eval_state, - &flake_lock_flags, - &flakeref_a, - ); - // Has not been locked and would need to write a lock file. - match locked_flake { - Ok(_) => panic!("Expected error, but got Ok"), - Err(e) => { - assert_eq!(e.to_string(), saved_err.to_string()); - }, - }; - - // Step 4: Update and write, succeeds flake_lock_flags - .set_mode(&FlakeLockMode::WriteAsNeeded) + .set_lock_mode(&FlakeLockMode::Virtual) .unwrap(); let locked_flake = LockedFlake::lock( @@ -368,110 +291,146 @@ mod tests { &flake_settings, &eval_state, &flake_lock_flags, - &flakeref_a, + &flake_ref_a, ) .unwrap(); - let outputs = locked_flake.outputs().unwrap(); + let outputs = locked_flake + .outputs(&flake_settings, &mut eval_state) + .unwrap(); - assert!(matches!(outputs, Value::Attrs(_))); - if let Value::Attrs(outputs) = outputs { - let value = outputs.get("hello").unwrap(); + let hello = eval_state.require_attrs_select(&outputs, "hello").unwrap(); + let hello = eval_state.require_string(&hello).unwrap(); - assert!(matches!(value, Value::String(_))); - if let Value::String(value) = value { - assert_eq!(value.as_string(), "ALICE"); - } - } + assert_eq!(hello, "BOB"); - // Step 5: Lock was written, so Step 1 succeeds - flake_lock_flags.set_mode(&FlakeLockMode::Check).unwrap(); + // Step 3: The lock was not written, so Step 1 would fail again + + flake_lock_flags + .set_lock_mode(&FlakeLockMode::Check) + .unwrap(); let locked_flake = LockedFlake::lock( &fetchers_settings, &flake_settings, &eval_state, &flake_lock_flags, - &flakeref_a, + &flake_ref_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) + .unwrap(); + + let locked_flake = LockedFlake::lock( + &fetchers_settings, + &flake_settings, + &eval_state, + &flake_lock_flags, + &flake_ref_a, ) .unwrap(); - let outputs = locked_flake.outputs().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"); - assert!(matches!(outputs, Value::Attrs(_))); - if let Value::Attrs(outputs) = outputs { - let value = outputs.get("hello").unwrap(); + // Step 5: Lock was written, so Step 1 succeeds - assert!(matches!(value, Value::String(_))); - if let Value::String(value) = value { - assert_eq!(value.as_string(), "ALICE"); - } - } + flake_lock_flags + .set_lock_mode(&FlakeLockMode::Check) + .unwrap(); + + let locked_flake = LockedFlake::lock( + &fetchers_settings, + &flake_settings, + &eval_state, + &flake_lock_flags, + &flake_ref_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"); // Step 6: Lock with override, do not write // This shouldn't matter; write_as_needed will be overridden flake_lock_flags - .set_mode(&FlakeLockMode::WriteAsNeeded) + .set_lock_mode(&FlakeLockMode::WriteAsNeeded) .unwrap(); - let flakeref_c = FlakeReference::parse( + let (flake_ref_c, fragment) = FlakeReference::parse_with_fragment( &fetchers_settings, &flake_settings, &flake_reference_parse_flags, &format!("path:{}", &flake_dir_c_str), ) .unwrap(); - assert_eq!(flakeref_c.fragment(), ""); + assert_eq!(fragment, ""); - flake_lock_flags.override_input("b", &flakeref_c).unwrap(); + flake_lock_flags.override_input("b", &flake_ref_c).unwrap(); let locked_flake = LockedFlake::lock( &fetchers_settings, &flake_settings, &eval_state, &flake_lock_flags, - &flakeref_a, + &flake_ref_a, ) .unwrap(); - let outputs = locked_flake.outputs().unwrap(); - - assert!(matches!(outputs, Value::Attrs(_))); - if let Value::Attrs(outputs) = outputs { - let value = outputs.get("hello").unwrap(); - - assert!(matches!(value, Value::String(_))); - if let Value::String(value) = value { - assert_eq!(value.as_string(), "Claire"); - } - } + 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"); // 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_mode(&FlakeLockMode::Check).unwrap(); + + flake_lock_flags + .set_lock_mode(&FlakeLockMode::Check) + .unwrap(); let locked_flake = LockedFlake::lock( &fetchers_settings, &flake_settings, &eval_state, &flake_lock_flags, - &flakeref_a, + &flake_ref_a, ) .unwrap(); - let outputs = locked_flake.outputs().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"); - 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"); - } - } + drop(fetchers_settings); + drop(tmp_dir); + drop(gc_registration); } } diff --git a/nixide/src/flake/mod.rs b/nixide/src/flake/mod.rs index 314173e..9ae171f 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; -use fetchers_settings::FetchersSettings; -use flake_lock_flags::{FlakeLockFlags, FlakeLockMode}; -use flake_reference::FlakeReference; -use flake_reference_parse_flags::FlakeReferenceParseFlags; +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; pub use flake_settings::FlakeSettings; pub use locked_flake::LockedFlake; diff --git a/nixide/src/init.rs b/nixide/src/init.rs deleted file mode 100644 index 7b85fb3..0000000 --- a/nixide/src/init.rs +++ /dev/null @@ -1,89 +0,0 @@ -use ctor::ctor; - -use super::NixideResult; -use super::errors::ErrorContext; -use super::util::wrap; -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) -/// > explicitly subverts that. The code that runs in `ctor` functions -/// > should be careful to limit itself to libc functions and code -/// > that does not rely on Rust's stdlib services. -/// > - Excerpt from the [github:mmastrac/rust-ctor README.md](https://github.com/mmastrac/rust-ctor?tab=readme-ov-file#warnings) -#[ctor] -#[cfg(not(feature = "exprs"))] -pub(crate) fn init_libutil() { - unsafe { - if !matches!(LIBNIX_INIT_STATUS, Some(Err(_))) { - LIBNIX_INIT_STATUS = Some(wrap::nix_fn!(|ctx: &ErrorContext| unsafe { - sys::nix_libutil_init(ctx.as_ptr()); - })); - } - } -} - -/// 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) -/// > explicitly subverts that. The code that runs in `ctor` functions -/// > should be careful to limit itself to libc functions and code -/// > that does not rely on Rust's stdlib services. -/// > - Excerpt from the [github:mmastrac/rust-ctor README.md](https://github.com/mmastrac/rust-ctor?tab=readme-ov-file#warnings) -#[ctor] -#[cfg(all(feature = "store", not(feature = "exprs")))] -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(_))) { - LIBNIX_INIT_STATUS = Some(wrap::nix_fn!(|ctx: &ErrorContext| unsafe { - sys::nix_libstore_init(ctx.as_ptr()); - })); - } - } -} - -/// 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 -/// -/// > Rust's philosophy is that nothing happens before or after main and [ctor](https://github.com/mmastrac/rust-ctor) -/// > explicitly subverts that. The code that runs in `ctor` functions -/// > should be careful to limit itself to libc functions and code -/// > that does not rely on Rust's stdlib services. -/// > - Excerpt from the [github:mmastrac/rust-ctor README.md](https://github.com/mmastrac/rust-ctor?tab=readme-ov-file#warnings) -#[ctor] -#[cfg(feature = "exprs")] -pub(crate) fn init_libexpr() { - unsafe { - if !matches!(LIBNIX_INIT_STATUS, Some(Err(_))) { - LIBNIX_INIT_STATUS = Some(wrap::nix_fn!(|ctx: &ErrorContext| unsafe { - sys::nix_libexpr_init(ctx.as_ptr()); - })); - } - } -} diff --git a/nixide/src/lib.rs b/nixide/src/lib.rs index 6b336f2..027aec7 100644 --- a/nixide/src/lib.rs +++ b/nixide/src/lib.rs @@ -7,8 +7,6 @@ pub extern crate libc; pub extern crate nixide_sys as sys; pub(crate) mod errors; -mod init; -mod nix_settings; mod stdext; pub(crate) mod util; mod verbosity; @@ -22,7 +20,6 @@ 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; @@ -32,3 +29,63 @@ pub use expr::{EvalState, EvalStateBuilder, Value}; pub use flake::{FlakeSettings, LockedFlake}; #[cfg(feature = "store")] pub use store::{Store, StorePath}; + +use ctor::ctor; +use util::wrappers::AsInnerPtr as _; + +pub(crate) static mut INIT_LIBUTIL_STATUS: Option> = None; +#[cfg(feature = "store")] +pub(crate) static mut INIT_LIBSTORE_STATUS: Option> = None; +#[cfg(feature = "exprs")] +pub(crate) static mut INIT_LIBEXPR_STATUS: Option> = None; + +/// # Warning +/// +/// > Rust's philosophy is that nothing happens before or after main and [ctor](https://github.com/mmastrac/rust-ctor) +/// > explicitly subverts that. The code that runs in `ctor` functions +/// > should be careful to limit itself to libc functions and code +/// > that does not rely on Rust's stdlib services. +/// > - Excerpt from the [github:mmastrac/rust-ctor README.md](https://github.com/mmastrac/rust-ctor?tab=readme-ov-file#warnings) +#[ctor] +fn init_libutil() { + unsafe { + INIT_LIBUTIL_STATUS = Some(util::wrap::nix_fn!(|ctx: &errors::ErrorContext| unsafe { + sys::nix_libutil_init(ctx.as_ptr()); + })); + } +} + +/// # Warning +/// +/// > Rust's philosophy is that nothing happens before or after main and [ctor](https://github.com/mmastrac/rust-ctor) +/// > explicitly subverts that. The code that runs in `ctor` functions +/// > should be careful to limit itself to libc functions and code +/// > that does not rely on Rust's stdlib services. +/// > - Excerpt from the [github:mmastrac/rust-ctor README.md](https://github.com/mmastrac/rust-ctor?tab=readme-ov-file#warnings) +#[ctor] +#[cfg(feature = "store")] +fn init_libstore() { + // XXX: TODO: how do I support `sys::nix_libstore_init_no_load_config(context)`? + unsafe { + INIT_LIBSTORE_STATUS = Some(util::wrap::nix_fn!(|ctx: &errors::ErrorContext| unsafe { + sys::nix_libutil_init(ctx.as_ptr()); + })); + } +} + +/// # Warning +/// +/// > Rust's philosophy is that nothing happens before or after main and [ctor](https://github.com/mmastrac/rust-ctor) +/// > explicitly subverts that. The code that runs in `ctor` functions +/// > should be careful to limit itself to libc functions and code +/// > that does not rely on Rust's stdlib services. +/// > - Excerpt from the [github:mmastrac/rust-ctor README.md](https://github.com/mmastrac/rust-ctor?tab=readme-ov-file#warnings) +#[ctor] +#[cfg(feature = "exprs")] +fn init_libexpr() { + unsafe { + INIT_LIBEXPR_STATUS = Some(util::wrap::nix_fn!(|ctx: &errors::ErrorContext| unsafe { + sys::nix_libexpr_init(ctx.as_ptr()); + })); + } +} diff --git a/nixide/src/nix_settings.rs b/nixide/src/nix_settings.rs index 21dd9a3..e69de29 100644 --- a/nixide/src/nix_settings.rs +++ b/nixide/src/nix_settings.rs @@ -1,37 +0,0 @@ -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 35c04e8..420d807 100644 --- a/nixide/src/store/mod.rs +++ b/nixide/src/store/mod.rs @@ -1,4 +1,13 @@ // 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)] @@ -7,38 +16,25 @@ mod tests; mod path; pub use path::*; -use std::ffi::{c_char, c_void}; +use std::ffi::{c_char, c_void, CString}; use std::path::PathBuf; -use std::ptr::{NonNull, null, null_mut}; +use std::ptr::{null, null_mut, NonNull}; +use std::result::Result; -use crate::NixideResult; -use crate::errors::ErrorContext; -use crate::stdext::{AsCPtr as _, CCharPtrExt as _}; +use crate::errors::{new_nixide_error, ErrorContext}; +use crate::stdext::CCharPtrExt; use crate::sys; +use crate::util::wrap; use crate::util::wrappers::AsInnerPtr; -use crate::util::{panic_issue_call_failed, wrap}; +use crate::{NixideError, NixideResult}; /// Nix store for managing packages and derivations. /// /// The store provides access to Nix packages, derivations, and store paths. -/// pub struct Store { - inner: NonNull, + pub(crate) 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 { @@ -67,19 +63,13 @@ impl Store { /// # Errors /// /// Returns an error if the store cannot be opened. - /// - pub fn open(uri: &str) -> NixideResult { - Self::open_ptr(uri.as_c_ptr()?) - } + 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(), + }; - /// 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()) @@ -105,7 +95,6 @@ impl Store { /// # Errors /// /// Returns an error if the path cannot be realized. - /// pub fn realise( &self, path: &StorePath, @@ -118,11 +107,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().unwrap_or_else(|err| panic_issue_call_failed!("{}", err)); + let output_name = output_name_ptr.to_utf8_string().expect("IDK1"); let inner = wrap::nix_ptr_fn!(|ctx| unsafe { sys::nix_store_path_clone(output_path_ptr as *mut sys::StorePath) - }).unwrap_or_else(|err| panic_issue_call_failed!("{}", err)); + }).expect("IDK2"); let store_path = StorePath { inner }; let callback = unsafe { (*userdata).inner }; @@ -172,16 +161,14 @@ impl Store { /// # Ok(()) /// # } /// ``` - /// - pub fn store_path(&self, path: &str) -> NixideResult { + pub fn store_path(&self, path: &str) -> Result { 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) -> NixideResult { + pub fn version(&self) -> Result { wrap::nix_string_callback!( |callback, userdata: *mut __UserData, ctx: &ErrorContext| unsafe { sys::nix_store_get_version( @@ -195,8 +182,7 @@ impl Store { } /// Get the URI of a Nix store - /// - pub fn uri(&self) -> NixideResult { + pub fn uri(&self) -> Result { wrap::nix_string_callback!( |callback, userdata: *mut __UserData, ctx: &ErrorContext| unsafe { sys::nix_store_get_uri( @@ -209,7 +195,7 @@ impl Store { ) } - pub fn store_dir(&self) -> NixideResult { + pub fn store_dir(&self) -> Result { wrap::nix_pathbuf_callback!( |callback, userdata: *mut __UserData, ctx: &ErrorContext| unsafe { sys::nix_store_get_storedir( @@ -222,26 +208,34 @@ impl Store { ) } - pub fn copy_closure_to(&self, dst_store: &Store, store_path: &StorePath) -> NixideResult<()> { + pub fn copy_closure_to( + &self, + dst_store: &Store, + store_path: &StorePath, + ) -> Result<(), NixideError> { 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) -> NixideResult<()> { + pub fn copy_closure_from( + &self, + src_store: &Store, + store_path: &StorePath, + ) -> Result<(), NixideError> { wrap::nix_fn!(|ctx: &ErrorContext| unsafe { sys::nix_store_copy_closure( ctx.as_ptr(), src_store.as_ptr(), self.as_ptr(), - store_path.as_ptr(), + store_path.inner.as_ptr(), ); - }) + }) // semi-colon to return () and not i32 } } @@ -252,3 +246,7 @@ 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 40c139b..d037c0e 100644 --- a/nixide/src/store/path.rs +++ b/nixide/src/store/path.rs @@ -1,14 +1,14 @@ -use std::ffi::{CString, c_void}; +use std::ffi::{c_void, CString}; use std::path::PathBuf; use std::ptr::NonNull; use super::Store; -use crate::NixideResult; -use crate::errors::{ErrorContext, new_nixide_error}; +use crate::errors::{new_nixide_error, ErrorContext}; 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,25 +18,6 @@ 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 { @@ -146,3 +127,26 @@ 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 5943077..da72ae7 100644 --- a/nixide/src/store/tests.rs +++ b/nixide/src/store/tests.rs @@ -2,24 +2,39 @@ 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() { - assert!(unsafe { matches!(LIBNIX_INIT_STATUS, Some(Ok(_))) }); + 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"); + }; - let _store = Store::default().expect("Failed to open store"); + let _store = Store::open(None).expect("Failed to open store"); } #[test] #[serial] fn test_store_path_parse() { - assert!(unsafe { matches!(LIBNIX_INIT_STATUS, Some(Ok(_))) }); + 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"); + }; - let store = Store::default().expect("Failed to open store"); + let store = Store::open(None).expect("Failed to open store"); // Try parsing a well-formed store path let result = StorePath::fake_path(&store); @@ -29,9 +44,17 @@ fn test_store_path_parse() { #[test] #[serial] fn test_store_path_clone() { - assert!(unsafe { matches!(LIBNIX_INIT_STATUS, Some(Ok(_))) }); + 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"); + }; - let store = Store::default().expect("Failed to open store"); + let store = Store::open(None).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`");