1#![cfg(feature = "expr")]
5
6use std::{ffi::CStr, fmt, ptr::NonNull, sync::Arc};
7
8use crate::{
9 Error,
10 EvalState,
11 Result,
12 error::check_err,
13 store,
14 sys,
15 value_ops,
16};
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub enum ValueType {
21 Thunk,
23 Int,
25 Float,
27 Bool,
29 String,
31 Path,
33 Null,
35 Attrs,
37 List,
39 Function,
41 External,
43}
44
45impl ValueType {
46 pub(crate) fn from_c(value_type: sys::ValueType) -> Self {
47 match value_type {
48 sys::ValueType_NIX_TYPE_THUNK => ValueType::Thunk,
49 sys::ValueType_NIX_TYPE_INT => ValueType::Int,
50 sys::ValueType_NIX_TYPE_FLOAT => ValueType::Float,
51 sys::ValueType_NIX_TYPE_BOOL => ValueType::Bool,
52 sys::ValueType_NIX_TYPE_STRING => ValueType::String,
53 sys::ValueType_NIX_TYPE_PATH => ValueType::Path,
54 sys::ValueType_NIX_TYPE_NULL => ValueType::Null,
55 sys::ValueType_NIX_TYPE_ATTRS => ValueType::Attrs,
56 sys::ValueType_NIX_TYPE_LIST => ValueType::List,
57 sys::ValueType_NIX_TYPE_FUNCTION => ValueType::Function,
58 sys::ValueType_NIX_TYPE_EXTERNAL => ValueType::External,
59 _ => ValueType::Thunk,
60 }
61 }
62}
63
64impl fmt::Display for ValueType {
65 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66 let name = match self {
67 ValueType::Thunk => "thunk",
68 ValueType::Int => "int",
69 ValueType::Float => "float",
70 ValueType::Bool => "bool",
71 ValueType::String => "string",
72 ValueType::Path => "path",
73 ValueType::Null => "null",
74 ValueType::Attrs => "attrs",
75 ValueType::List => "list",
76 ValueType::Function => "function",
77 ValueType::External => "external",
78 };
79 write!(f, "{name}")
80 }
81}
82
83pub struct Value<'a> {
89 pub(crate) inner: NonNull<sys::nix_value>,
90 pub(crate) state: &'a EvalState,
91}
92
93impl value_ops::NixValueRaw for Value<'_> {
94 fn raw_ctx(&self) -> *mut sys::nix_c_context {
95 unsafe { self.state.context.as_ptr() }
97 }
98
99 fn raw_state(&self) -> *mut sys::EvalState {
100 unsafe { self.state.as_ptr() }
102 }
103
104 fn raw_inner(&self) -> *mut sys::nix_value {
105 self.inner.as_ptr()
106 }
107}
108
109impl Value<'_> {
110 pub fn force(&mut self) -> Result<()> {
118 self.force_shared()
119 }
120
121 pub fn force_deep(&mut self) -> Result<()> {
129 unsafe {
131 check_err(
132 self.state.context.as_ptr(),
133 sys::nix_value_force_deep(
134 self.state.context.as_ptr(),
135 self.state.as_ptr(),
136 self.inner.as_ptr(),
137 ),
138 )
139 }
140 }
141
142 #[must_use]
148 pub fn value_type(&self) -> ValueType {
149 let c_type = unsafe {
151 sys::nix_get_type(self.state.context.as_ptr(), self.inner.as_ptr())
152 };
153 ValueType::from_c(c_type)
154 }
155
156 #[must_use]
162 pub fn type_name(&self) -> String {
163 let ptr = unsafe {
165 sys::nix_get_typename(self.state.context.as_ptr(), self.inner.as_ptr())
166 };
167 if ptr.is_null() {
168 return self.value_type().to_string();
169 }
170 let s = unsafe { CStr::from_ptr(ptr) }
172 .to_string_lossy()
173 .into_owned();
174 unsafe extern "C" {
177 fn free(ptr: *mut std::os::raw::c_void);
178 }
179 unsafe { free(ptr.cast_mut().cast()) };
181 s
182 }
183
184 pub(crate) fn force_shared(&self) -> Result<()> {
190 unsafe {
192 check_err(
193 self.state.context.as_ptr(),
194 sys::nix_value_force(
195 self.state.context.as_ptr(),
196 self.state.as_ptr(),
197 self.inner.as_ptr(),
198 ),
199 )
200 }
201 }
202
203 pub fn as_int(&self) -> Result<i64> {
210 self.force_shared()?;
211 if self.value_type() != ValueType::Int {
212 return Err(Error::InvalidType {
213 expected: "int",
214 actual: self.value_type().to_string(),
215 });
216 }
217 Ok(unsafe {
219 sys::nix_get_int(self.state.context.as_ptr(), self.inner.as_ptr())
220 })
221 }
222
223 pub fn as_float(&self) -> Result<f64> {
230 self.force_shared()?;
231 if self.value_type() != ValueType::Float {
232 return Err(Error::InvalidType {
233 expected: "float",
234 actual: self.value_type().to_string(),
235 });
236 }
237 Ok(unsafe {
239 sys::nix_get_float(self.state.context.as_ptr(), self.inner.as_ptr())
240 })
241 }
242
243 pub fn as_bool(&self) -> Result<bool> {
250 self.force_shared()?;
251 if self.value_type() != ValueType::Bool {
252 return Err(Error::InvalidType {
253 expected: "bool",
254 actual: self.value_type().to_string(),
255 });
256 }
257 Ok(unsafe {
259 sys::nix_get_bool(self.state.context.as_ptr(), self.inner.as_ptr())
260 })
261 }
262
263 pub fn as_string(&self) -> Result<String> {
271 self.force_shared()?;
272 if self.value_type() != ValueType::String {
273 return Err(Error::InvalidType {
274 expected: "string",
275 actual: self.value_type().to_string(),
276 });
277 }
278
279 let realised_str = unsafe {
281 sys::nix_string_realise(
282 self.state.context.as_ptr(),
283 self.state.as_ptr(),
284 self.inner.as_ptr(),
285 false,
286 )
287 };
288
289 if realised_str.is_null() {
290 return Err(Error::NullPointer);
291 }
292
293 let buffer_start =
294 unsafe { sys::nix_realised_string_get_buffer_start(realised_str) };
295 let buffer_size =
296 unsafe { sys::nix_realised_string_get_buffer_size(realised_str) };
297
298 if buffer_start.is_null() {
299 unsafe { sys::nix_realised_string_free(realised_str) };
300 return Err(Error::NullPointer);
301 }
302
303 let bytes = unsafe {
304 std::slice::from_raw_parts(buffer_start.cast::<u8>(), buffer_size)
305 };
306 let string = std::str::from_utf8(bytes)
307 .map_err(|_| Error::Unknown("Invalid UTF-8 in string".to_string()))?
308 .to_owned();
309
310 unsafe { sys::nix_realised_string_free(realised_str) };
311
312 Ok(string)
313 }
314
315 pub fn as_string_with_context(
325 &self,
326 ) -> Result<(String, Vec<store::StorePath>)> {
327 self.force_shared()?;
328 if self.value_type() != ValueType::String {
329 return Err(Error::InvalidType {
330 expected: "string",
331 actual: self.value_type().to_string(),
332 });
333 }
334
335 let realised_str = unsafe {
337 sys::nix_string_realise(
338 self.state.context.as_ptr(),
339 self.state.as_ptr(),
340 self.inner.as_ptr(),
341 false,
342 )
343 };
344
345 if realised_str.is_null() {
346 return Err(Error::NullPointer);
347 }
348
349 let buffer_start =
350 unsafe { sys::nix_realised_string_get_buffer_start(realised_str) };
351 let buffer_size =
352 unsafe { sys::nix_realised_string_get_buffer_size(realised_str) };
353
354 if buffer_start.is_null() {
355 unsafe { sys::nix_realised_string_free(realised_str) };
356 return Err(Error::NullPointer);
357 }
358
359 let bytes = unsafe {
360 std::slice::from_raw_parts(buffer_start.cast::<u8>(), buffer_size)
361 };
362 let string = match std::str::from_utf8(bytes) {
363 Ok(s) => s.to_owned(),
364 Err(_) => {
365 unsafe { sys::nix_realised_string_free(realised_str) };
366 return Err(Error::Unknown("Invalid UTF-8 in string".to_string()));
367 },
368 };
369
370 let count =
371 unsafe { sys::nix_realised_string_get_store_path_count(realised_str) };
372 let mut paths = Vec::with_capacity(count);
373 for i in 0..count {
374 let raw =
376 unsafe { sys::nix_realised_string_get_store_path(realised_str, i) };
377 if raw.is_null() {
378 continue;
379 }
380 let cloned =
381 unsafe { sys::nix_store_path_clone(raw as *mut sys::StorePath) };
382 if let Some(inner) = NonNull::new(cloned) {
383 paths.push(store::StorePath {
384 inner,
385 _context: Arc::clone(&self.state.context),
386 });
387 }
388 }
389
390 unsafe { sys::nix_realised_string_free(realised_str) };
391
392 Ok((string, paths))
393 }
394
395 pub fn as_path(&self) -> Result<std::path::PathBuf> {
401 self.force_shared()?;
402 if self.value_type() != ValueType::Path {
403 return Err(Error::InvalidType {
404 expected: "path",
405 actual: self.value_type().to_string(),
406 });
407 }
408
409 let path_ptr = unsafe {
411 sys::nix_get_path_string(self.state.context.as_ptr(), self.inner.as_ptr())
412 };
413
414 if path_ptr.is_null() {
415 return Err(Error::NullPointer);
416 }
417
418 #[cfg(unix)]
421 {
422 use std::os::unix::ffi::OsStrExt as _;
423 let bytes = unsafe { CStr::from_ptr(path_ptr) }.to_bytes();
424 Ok(std::path::PathBuf::from(std::ffi::OsStr::from_bytes(bytes)))
425 }
426 #[cfg(not(unix))]
427 {
428 let path_str =
429 unsafe { CStr::from_ptr(path_ptr).to_string_lossy().into_owned() };
430 Ok(std::path::PathBuf::from(path_str))
431 }
432 }
433
434 pub fn call(&self, arg: &Value<'_>) -> Result<Value<'_>> {
440 let result = self.state.alloc_value()?;
441 unsafe {
443 check_err(
444 self.state.context.as_ptr(),
445 sys::nix_value_call(
446 self.state.context.as_ptr(),
447 self.state.as_ptr(),
448 self.inner.as_ptr(),
449 arg.inner.as_ptr(),
450 result.inner.as_ptr(),
451 ),
452 )?;
453 }
454 Ok(result)
455 }
456
457 pub fn call_multi(&self, args: &[&Value<'_>]) -> Result<Value<'_>> {
463 let result = self.state.alloc_value()?;
464 let mut arg_ptrs: Vec<*mut sys::nix_value> =
465 args.iter().map(|a| a.inner.as_ptr()).collect();
466 unsafe {
468 check_err(
469 self.state.context.as_ptr(),
470 sys::nix_value_call_multi(
471 self.state.context.as_ptr(),
472 self.state.as_ptr(),
473 self.inner.as_ptr(),
474 arg_ptrs.len(),
475 arg_ptrs.as_mut_ptr(),
476 result.inner.as_ptr(),
477 ),
478 )?;
479 }
480 Ok(result)
481 }
482
483 pub fn make_thunk<'a>(
493 fn_val: &'a Value<'a>,
494 arg: &'a Value<'a>,
495 ) -> Result<Value<'a>> {
496 let result = fn_val.state.alloc_value()?;
497 unsafe {
499 check_err(
500 fn_val.state.context.as_ptr(),
501 sys::nix_init_apply(
502 fn_val.state.context.as_ptr(),
503 result.inner.as_ptr(),
504 fn_val.inner.as_ptr(),
505 arg.inner.as_ptr(),
506 ),
507 )?;
508 }
509 Ok(result)
510 }
511
512 pub fn copy(&self) -> Result<Value<'_>> {
518 let result = self.state.alloc_value()?;
519 unsafe {
521 check_err(
522 self.state.context.as_ptr(),
523 sys::nix_copy_value(
524 self.state.context.as_ptr(),
525 result.inner.as_ptr(),
526 self.inner.as_ptr(),
527 ),
528 )?;
529 }
530 Ok(result)
531 }
532
533 pub fn to_nix_string(&self) -> Result<String> {
545 self.force_shared()?;
546 match self.value_type() {
547 ValueType::Int => Ok(self.as_int()?.to_string()),
548 ValueType::Float => Ok(self.as_float()?.to_string()),
549 ValueType::Bool => {
550 Ok(if self.as_bool()? { "true" } else { "false" }.to_string())
551 },
552 ValueType::String => {
553 let s = self.as_string()?;
554 Ok(format!(
555 "\"{}\"",
556 s.replace('\\', "\\\\").replace('"', "\\\"")
557 ))
558 },
559 ValueType::Null => Ok("null".to_string()),
560 ValueType::Path => {
561 Ok(
562 self
563 .as_path()
564 .map_or_else(|_| "<path>".to_string(), |p| p.display().to_string()),
565 )
566 },
567 ValueType::Attrs => {
568 let mut parts = Vec::new();
569 for entry in self.attrs()? {
570 let (k, v) = entry?;
571 parts.push(format!("{k} = {};", v.to_nix_string()?));
572 }
573 if parts.is_empty() {
574 Ok("{ }".to_string())
575 } else {
576 Ok(format!("{{ {} }}", parts.join(" ")))
577 }
578 },
579 ValueType::List => {
580 let mut parts = Vec::new();
581 for entry in self.list_iter()? {
582 parts.push(entry?.to_nix_string()?);
583 }
584 if parts.is_empty() {
585 Ok("[ ]".to_string())
586 } else {
587 Ok(format!("[ {} ]", parts.join(" ")))
588 }
589 },
590 ValueType::Function => Ok("<lambda>".to_string()),
591 ValueType::Thunk => Ok("<thunk>".to_string()),
592 ValueType::External => Ok("<external>".to_string()),
593 }
594 }
595}
596
597impl Drop for Value<'_> {
598 fn drop(&mut self) {
599 unsafe {
601 sys::nix_value_decref(self.state.context.as_ptr(), self.inner.as_ptr());
602 }
603 }
604}
605
606impl<'a> Clone for Value<'a> {
607 fn clone(&self) -> Self {
613 let err = unsafe {
615 sys::nix_value_incref(self.state.context.as_ptr(), self.inner.as_ptr())
616 };
617 assert!(
618 err == sys::nix_err_NIX_OK,
619 "nix_value_incref failed with code {err}"
620 );
621 Value {
622 inner: self.inner,
623 state: self.state,
624 }
625 }
626}
627
628impl fmt::Display for Value<'_> {
629 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
630 match self.value_type() {
631 ValueType::Int => {
632 match self.as_int() {
633 Ok(v) => write!(f, "{v}"),
634 Err(_) => write!(f, "<int error>"),
635 }
636 },
637 ValueType::Float => {
638 match self.as_float() {
639 Ok(v) => write!(f, "{v}"),
640 Err(_) => write!(f, "<float error>"),
641 }
642 },
643 ValueType::Bool => {
644 match self.as_bool() {
645 Ok(v) => write!(f, "{v}"),
646 Err(_) => write!(f, "<bool error>"),
647 }
648 },
649 ValueType::String => {
650 match self.as_string() {
651 Ok(v) => write!(f, "{v}"),
652 Err(_) => write!(f, "<string error>"),
653 }
654 },
655 ValueType::Null => write!(f, "null"),
656 ValueType::Attrs => write!(f, "{{ <attrs> }}"),
657 ValueType::List => write!(f, "[ <list> ]"),
658 ValueType::Function => write!(f, "<function>"),
659 ValueType::Path => {
660 match self.as_path() {
661 Ok(p) => write!(f, "{}", p.display()),
662 Err(_) => write!(f, "<path>"),
663 }
664 },
665 ValueType::Thunk => write!(f, "<thunk>"),
666 ValueType::External => write!(f, "<external>"),
667 }
668 }
669}
670
671impl fmt::Debug for Value<'_> {
672 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
673 let value_type = self.value_type();
674 match value_type {
675 ValueType::Int => {
676 match self.as_int() {
677 Ok(v) => write!(f, "Value::Int({v})"),
678 Err(_) => write!(f, "Value::Int(<error>)"),
679 }
680 },
681 ValueType::Float => {
682 match self.as_float() {
683 Ok(v) => write!(f, "Value::Float({v})"),
684 Err(_) => write!(f, "Value::Float(<error>)"),
685 }
686 },
687 ValueType::Bool => {
688 match self.as_bool() {
689 Ok(v) => write!(f, "Value::Bool({v})"),
690 Err(_) => write!(f, "Value::Bool(<error>)"),
691 }
692 },
693 ValueType::String => {
694 match self.as_string() {
695 Ok(v) => write!(f, "Value::String({v:?})"),
696 Err(_) => write!(f, "Value::String(<error>)"),
697 }
698 },
699 ValueType::Null => write!(f, "Value::Null"),
700 ValueType::Attrs => write!(f, "Value::Attrs({{ <attrs> }})"),
701 ValueType::List => write!(f, "Value::List([ <list> ])"),
702 ValueType::Function => write!(f, "Value::Function(<function>)"),
703 ValueType::Path => {
704 match self.as_path() {
705 Ok(p) => write!(f, "Value::Path({})", p.display()),
706 Err(_) => write!(f, "Value::Path(<path>)"),
707 }
708 },
709 ValueType::Thunk => write!(f, "Value::Thunk(<thunk>)"),
710 ValueType::External => write!(f, "Value::External(<external>)"),
711 }
712 }
713}