104 lines
3.5 KiB
Rust
104 lines
3.5 KiB
Rust
use std::cell::RefCell;
|
|
use std::ffi::c_char;
|
|
use std::ptr::NonNull;
|
|
|
|
use crate::errors::ErrorContext;
|
|
use crate::expr::values::NixString;
|
|
use crate::stdext::CCharPtrExt;
|
|
use crate::util::LazyArray;
|
|
use crate::util::wrappers::AsInnerPtr;
|
|
use crate::util::{panic_issue_call_failed, wrap};
|
|
use crate::{EvalState, NixideResult, StorePath};
|
|
use crate::{Store, sys};
|
|
|
|
pub struct RealisedString<'a> {
|
|
inner: RefCell<NonNull<sys::nix_realised_string>>,
|
|
pub path: StorePath,
|
|
pub children: LazyArray<StorePath, Box<dyn Fn(usize) -> StorePath + 'a>>,
|
|
}
|
|
|
|
impl<'a> AsInnerPtr<sys::nix_realised_string> for RealisedString<'a> {
|
|
#[inline]
|
|
unsafe fn as_ptr(&self) -> *mut sys::nix_realised_string {
|
|
self.inner.borrow().as_ptr()
|
|
}
|
|
|
|
#[inline]
|
|
unsafe fn as_ref(&self) -> &sys::nix_realised_string {
|
|
unsafe { self.inner.borrow().as_ref() }
|
|
}
|
|
|
|
#[inline]
|
|
unsafe fn as_mut(&mut self) -> &mut sys::nix_realised_string {
|
|
unsafe { self.inner.borrow_mut().as_mut() }
|
|
}
|
|
}
|
|
|
|
impl<'a> Drop for RealisedString<'a> {
|
|
fn drop(&mut self) {
|
|
unsafe {
|
|
sys::nix_realised_string_free(self.as_ptr());
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> RealisedString<'a> {
|
|
/// Realise a string context.
|
|
///
|
|
/// This will
|
|
/// - realise the store paths referenced by the string's content, and
|
|
/// - perform the replacement of placeholders.
|
|
/// - create temporary garbage collection roots for the store paths, for
|
|
/// the lifetime of the current process.
|
|
/// - log to stderr
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * value - Nix value, which must be a string
|
|
/// * state - Nix evaluator state
|
|
/// * isIFD - If true, disallow derivation outputs if setting `allow-import-from-derivation` is false.
|
|
/// You should set this to true when this call is part of a primop.
|
|
/// You should set this to false when building for your application's purpose.
|
|
///
|
|
pub fn new(value: &NixString, state: &'a EvalState) -> NixideResult<RealisedString<'a>> {
|
|
let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe {
|
|
sys::nix_string_realise(
|
|
ctx.as_ptr(),
|
|
state.as_ptr(),
|
|
value.as_ptr(),
|
|
false, // don't copy more
|
|
)
|
|
})?;
|
|
|
|
let size = unsafe { sys::nix_realised_string_get_store_path_count(inner.as_ptr()) };
|
|
|
|
Ok(Self {
|
|
inner: RefCell::new(inner),
|
|
path: Self::parse_path(inner.as_ptr(), &state.store_ref().borrow()),
|
|
children: LazyArray::new(
|
|
size,
|
|
Box::new(|_| StorePath::fake_path(&state.store_ref().borrow()).unwrap()),
|
|
),
|
|
})
|
|
}
|
|
|
|
fn parse_path(realised_string: *mut sys::nix_realised_string, store: &Store) -> StorePath {
|
|
let buffer_ptr = unsafe { sys::nix_realised_string_get_buffer_start(realised_string) };
|
|
let buffer_size = unsafe { sys::nix_realised_string_get_buffer_size(realised_string) };
|
|
|
|
let path_str = (buffer_ptr as *const c_char)
|
|
.to_utf8_string_n(buffer_size)
|
|
.unwrap_or_else(|err| {
|
|
panic_issue_call_failed!(
|
|
"`sys::nix_realised_string_get_buffer_(start|size)` invalid UTF-8 ({})",
|
|
err
|
|
)
|
|
});
|
|
StorePath::parse(store, &path_str).unwrap_or_else(|err| {
|
|
panic_issue_call_failed!(
|
|
"`sys::nix_realised_string_get_buffer_(start|size)` invalid store path ({})",
|
|
err
|
|
)
|
|
})
|
|
}
|
|
}
|