1#![warn(missing_docs)]
2#![cfg_attr(test, allow(clippy::arc_with_non_send_sync))]
9#[doc(hidden)]
125pub mod sys {
126 pub use nix_bindings_sys::*;
127}
128
129mod error;
130pub use error::{Error, Result};
131#[cfg(feature = "store")]
135pub(crate) use error::{
136 check_err,
137 check_ptr,
138 checked_string_from_callback,
139 string_from_callback,
140};
141
142#[cfg(feature = "store")] mod context;
143#[cfg(feature = "store")]
144pub use context::{Context, Verbosity, is_pure_eval, nix_version};
145
146#[cfg(feature = "store")] mod store;
147#[cfg(feature = "store")]
148pub use store::{Derivation, Store, StorePath};
149
150#[cfg(feature = "expr")] mod attrs;
151#[cfg(feature = "expr")] mod eval;
152#[cfg(feature = "expr")] mod lists;
153#[cfg(feature = "expr")] mod value;
154#[cfg(feature = "expr")] mod value_ops;
155
156#[cfg(feature = "expr")]
157pub use eval::{EvalState, EvalStateBuilder};
158#[cfg(feature = "expr")] pub use value::{Value, ValueType};
159#[cfg(feature = "expr")] pub use value_ops::NixValueOps;
160
161#[cfg(feature = "external")] pub mod external;
162#[cfg(feature = "flake")] pub mod flake;
163#[cfg(feature = "primop")] pub mod primop;
164
165#[cfg(all(test, any(feature = "store", feature = "expr")))]
166mod tests {
167 #[cfg(feature = "expr")] use std::sync::Arc;
168
169 #[cfg(feature = "expr")] use serial_test::serial;
170
171 #[cfg(feature = "store")] use super::*;
172
173 #[cfg(feature = "store")]
174 #[test]
175 #[serial]
176 fn test_context_creation() {
177 let _ctx = Context::new().expect("Failed to create context");
178 }
179
180 #[cfg(feature = "store")]
181 #[test]
182 #[serial]
183 fn test_nix_version() {
184 let version = nix_version();
185 assert!(!version.is_empty(), "Version should not be empty");
186 }
187
188 #[cfg(feature = "expr")]
189 #[test]
190 #[serial]
191 fn test_eval_state_builder() {
192 let ctx = Arc::new(Context::new().expect("Failed to create context"));
193 let store =
194 Arc::new(Store::open(&ctx, None).expect("Failed to open store"));
195 let _state = EvalStateBuilder::new(&store)
196 .expect("Failed to create builder")
197 .build()
198 .expect("Failed to build state");
199 }
200
201 #[cfg(feature = "expr")]
202 #[test]
203 #[serial]
204 fn test_simple_evaluation() {
205 let ctx = Arc::new(Context::new().expect("Failed to create context"));
206 let store =
207 Arc::new(Store::open(&ctx, None).expect("Failed to open store"));
208 let state = EvalStateBuilder::new(&store)
209 .expect("Failed to create builder")
210 .build()
211 .expect("Failed to build state");
212
213 let result = state
214 .eval_from_string("1 + 2", "<eval>")
215 .expect("Failed to evaluate expression");
216
217 assert_eq!(result.value_type(), ValueType::Int);
218 assert_eq!(result.as_int().expect("Failed to get int value"), 3);
219 }
220
221 #[cfg(feature = "expr")]
222 #[test]
223 #[serial]
224 fn test_value_types() {
225 let ctx = Arc::new(Context::new().expect("Failed to create context"));
226 let store =
227 Arc::new(Store::open(&ctx, None).expect("Failed to open store"));
228 let state = EvalStateBuilder::new(&store)
229 .expect("Failed to create builder")
230 .build()
231 .expect("Failed to build state");
232
233 let int_val = state
234 .eval_from_string("42", "<eval>")
235 .expect("Failed to evaluate int");
236 assert_eq!(int_val.value_type(), ValueType::Int);
237 assert_eq!(int_val.as_int().expect("Failed to get int"), 42);
238
239 let bool_val = state
240 .eval_from_string("true", "<eval>")
241 .expect("Failed to evaluate bool");
242 assert_eq!(bool_val.value_type(), ValueType::Bool);
243 assert!(bool_val.as_bool().expect("Failed to get bool"));
244
245 let str_val = state
246 .eval_from_string("\"hello\"", "<eval>")
247 .expect("Failed to evaluate string");
248 assert_eq!(str_val.value_type(), ValueType::String);
249 assert_eq!(str_val.as_string().expect("Failed to get string"), "hello");
250 }
251
252 #[cfg(feature = "expr")]
253 #[test]
254 #[serial]
255 fn test_value_construction() {
256 let ctx = Arc::new(Context::new().expect("Failed to create context"));
257 let store =
258 Arc::new(Store::open(&ctx, None).expect("Failed to open store"));
259 let state = EvalStateBuilder::new(&store)
260 .expect("Failed to create builder")
261 .build()
262 .expect("Failed to build state");
263
264 let int_val = state.make_int(99).expect("Failed to make int");
265 assert_eq!(int_val.as_int().unwrap(), 99);
266
267 let float_val = state.make_float(2.5).expect("Failed to make float");
268 assert!((float_val.as_float().unwrap() - 2.5).abs() < 1e-9);
269
270 let bool_val = state.make_bool(true).expect("Failed to make bool");
271 assert!(bool_val.as_bool().unwrap());
272
273 let null_val = state.make_null().expect("Failed to make null");
274 assert_eq!(null_val.value_type(), ValueType::Null);
275
276 let str_val = state.make_string("hello").expect("Failed to make string");
277 assert_eq!(str_val.as_string().unwrap(), "hello");
278 }
279
280 #[cfg(feature = "expr")]
281 #[test]
282 #[serial]
283 fn test_make_list() {
284 let ctx = Arc::new(Context::new().expect("Failed to create context"));
285 let store =
286 Arc::new(Store::open(&ctx, None).expect("Failed to open store"));
287 let state = EvalStateBuilder::new(&store)
288 .expect("Failed to create builder")
289 .build()
290 .expect("Failed to build state");
291
292 let a = state.make_int(1).unwrap();
293 let b = state.make_int(2).unwrap();
294 let c = state.make_int(3).unwrap();
295
296 let list = state.make_list(&[&a, &b, &c]).expect("Failed to make list");
297 assert_eq!(list.value_type(), ValueType::List);
298 assert_eq!(list.list_len().unwrap(), 3);
299 }
300
301 #[cfg(feature = "expr")]
302 #[test]
303 #[serial]
304 fn test_make_attrs() {
305 let ctx = Arc::new(Context::new().expect("Failed to create context"));
306 let store =
307 Arc::new(Store::open(&ctx, None).expect("Failed to open store"));
308 let state = EvalStateBuilder::new(&store)
309 .expect("Failed to create builder")
310 .build()
311 .expect("Failed to build state");
312
313 let a = state.make_int(42).unwrap();
314 let b = state.make_string("hello").unwrap();
315
316 let attrs = state
317 .make_attrs(&[("answer", &a), ("greeting", &b)])
318 .expect("Failed to make attrs");
319 assert_eq!(attrs.value_type(), ValueType::Attrs);
320
321 let answer = attrs.get_attr("answer").unwrap();
322 assert_eq!(answer.as_int().unwrap(), 42);
324 }
325
326 #[cfg(feature = "expr")]
327 #[test]
328 #[serial]
329 fn test_value_call() {
330 let ctx = Arc::new(Context::new().expect("Failed to create context"));
331 let store =
332 Arc::new(Store::open(&ctx, None).expect("Failed to open store"));
333 let state = EvalStateBuilder::new(&store)
334 .expect("Failed to create builder")
335 .build()
336 .expect("Failed to build state");
337
338 let f = state
339 .eval_from_string("x: x + 1", "<eval>")
340 .expect("Failed to evaluate function");
341 let arg = state.make_int(41).unwrap();
342 let result = f.call(&arg).expect("Failed to call function");
343 assert_eq!(result.as_int().unwrap(), 42);
344 }
345
346 #[cfg(feature = "expr")]
347 #[test]
348 #[serial]
349 fn test_value_copy() {
350 let ctx = Arc::new(Context::new().expect("Failed to create context"));
351 let store =
352 Arc::new(Store::open(&ctx, None).expect("Failed to open store"));
353 let state = EvalStateBuilder::new(&store)
354 .expect("Failed to create builder")
355 .build()
356 .expect("Failed to build state");
357
358 let orig = state.make_int(7).unwrap();
359 let copy = orig.copy().expect("Failed to copy value");
360 assert_eq!(copy.as_int().unwrap(), 7);
361 }
362
363 #[cfg(feature = "expr")]
364 #[test]
365 #[serial]
366 fn test_as_string_with_context_plain() {
367 let ctx = Arc::new(Context::new().expect("Failed to create context"));
368 let store =
369 Arc::new(Store::open(&ctx, None).expect("Failed to open store"));
370 let state = EvalStateBuilder::new(&store)
371 .expect("Failed to create builder")
372 .build()
373 .expect("Failed to build state");
374
375 let val = state
376 .eval_from_string("\"hello\"", "<eval>")
377 .expect("Failed to evaluate string");
378 let (s, ctx_paths) = val
379 .as_string_with_context()
380 .expect("as_string_with_context failed");
381 assert_eq!(s, "hello");
382 assert!(
383 ctx_paths.is_empty(),
384 "Plain string should have no context paths"
385 );
386 }
387
388 #[cfg(feature = "expr")]
389 #[test]
390 #[serial]
391 fn test_eval_from_file() {
392 use std::io::Write as _;
393 let ctx = Arc::new(Context::new().expect("Failed to create context"));
394 let store =
395 Arc::new(Store::open(&ctx, None).expect("Failed to open store"));
396 let state = EvalStateBuilder::new(&store)
397 .expect("Failed to create builder")
398 .build()
399 .expect("Failed to build state");
400
401 let mut tmp =
402 tempfile::NamedTempFile::new().expect("Failed to create temp file");
403 write!(tmp, "1 + 1").expect("Failed to write temp file");
404 let result = state
405 .eval_from_file(tmp.path())
406 .expect("eval_from_file failed");
407 assert_eq!(result.as_int().unwrap(), 2);
408 }
409
410 #[cfg(feature = "expr")]
411 #[test]
412 #[serial]
413 fn test_no_load_config() {
414 let ctx = Arc::new(Context::new().expect("Failed to create context"));
415 let store =
416 Arc::new(Store::open(&ctx, None).expect("Failed to open store"));
417 let state = EvalStateBuilder::new(&store)
418 .expect("Failed to create builder")
419 .no_load_config()
420 .build()
421 .expect("Failed to build state with no_load_config");
422 let val = state
423 .eval_from_string("1 + 1", "<eval>")
424 .expect("Evaluation failed");
425 assert_eq!(val.as_int().unwrap(), 2);
426 }
427}