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