nix_bindings/
value_ops.rs1use std::ffi::CStr;
15
16use crate::{Error, Result, ValueType, check_err, sys};
17
18pub(crate) mod sealed {
19 use super::sys;
20
21 pub trait NixValueRaw {
22 fn raw_ctx(&self) -> *mut sys::nix_c_context;
23 fn raw_state(&self) -> *mut sys::EvalState;
24 fn raw_inner(&self) -> *mut sys::nix_value;
25 }
26}
27
28pub(crate) use sealed::NixValueRaw;
33
34pub trait NixValueOps: sealed::NixValueRaw {
42 fn value_type(&self) -> ValueType {
47 let c_type = unsafe { sys::nix_get_type(self.raw_ctx(), self.raw_inner()) };
49 ValueType::from_c(c_type)
50 }
51
52 fn force(&self) -> Result<()> {
58 unsafe {
60 check_err(
61 self.raw_ctx(),
62 sys::nix_value_force(
63 self.raw_ctx(),
64 self.raw_state(),
65 self.raw_inner(),
66 ),
67 )
68 }
69 }
70
71 fn as_int(&self) -> Result<i64> {
78 self.force()?;
79 if self.value_type() != ValueType::Int {
80 return Err(Error::InvalidType {
81 expected: "int",
82 actual: self.value_type().to_string(),
83 });
84 }
85 Ok(unsafe { sys::nix_get_int(self.raw_ctx(), self.raw_inner()) })
87 }
88
89 fn as_float(&self) -> Result<f64> {
96 self.force()?;
97 if self.value_type() != ValueType::Float {
98 return Err(Error::InvalidType {
99 expected: "float",
100 actual: self.value_type().to_string(),
101 });
102 }
103 Ok(unsafe { sys::nix_get_float(self.raw_ctx(), self.raw_inner()) })
105 }
106
107 fn as_bool(&self) -> Result<bool> {
114 self.force()?;
115 if self.value_type() != ValueType::Bool {
116 return Err(Error::InvalidType {
117 expected: "bool",
118 actual: self.value_type().to_string(),
119 });
120 }
121 Ok(unsafe { sys::nix_get_bool(self.raw_ctx(), self.raw_inner()) })
123 }
124
125 fn as_string(&self) -> Result<String> {
133 self.force()?;
134 if self.value_type() != ValueType::String {
135 return Err(Error::InvalidType {
136 expected: "string",
137 actual: self.value_type().to_string(),
138 });
139 }
140
141 let realised_str = unsafe {
143 sys::nix_string_realise(
144 self.raw_ctx(),
145 self.raw_state(),
146 self.raw_inner(),
147 false,
148 )
149 };
150
151 if realised_str.is_null() {
152 return Err(Error::NullPointer);
153 }
154
155 let buffer_start =
156 unsafe { sys::nix_realised_string_get_buffer_start(realised_str) };
157 let buffer_size =
158 unsafe { sys::nix_realised_string_get_buffer_size(realised_str) };
159
160 if buffer_start.is_null() {
161 unsafe { sys::nix_realised_string_free(realised_str) };
162 return Err(Error::NullPointer);
163 }
164
165 let bytes = unsafe {
166 std::slice::from_raw_parts(buffer_start.cast::<u8>(), buffer_size)
167 };
168 let s = std::str::from_utf8(bytes)
169 .map_err(|_| Error::Unknown("Invalid UTF-8 in string".into()))?
170 .to_owned();
171
172 unsafe { sys::nix_realised_string_free(realised_str) };
173 Ok(s)
174 }
175
176 fn as_path(&self) -> Result<String> {
183 self.force()?;
184 if self.value_type() != ValueType::Path {
185 return Err(Error::InvalidType {
186 expected: "path",
187 actual: self.value_type().to_string(),
188 });
189 }
190 let raw =
192 unsafe { sys::nix_get_path_string(self.raw_ctx(), self.raw_inner()) };
193 if raw.is_null() {
194 return Err(Error::NullPointer);
195 }
196 let cstr = unsafe { CStr::from_ptr(raw) };
197 cstr
198 .to_str()
199 .map(str::to_owned)
200 .map_err(|_| Error::Unknown("Invalid UTF-8 in path".into()))
201 }
202}
203
204impl<T: sealed::NixValueRaw> NixValueOps for T {}