Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/libexpr-c/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ subdir('nix-meson-build-support/subprojects')
subdir('nix-meson-build-support/common')

sources = files(
'nix_api_eval.cc',
'nix_api_expr.cc',
'nix_api_external.cc',
'nix_api_value.cc',
Expand Down
55 changes: 55 additions & 0 deletions src/libexpr-c/nix_api_eval.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#include "nix/expr/eval.hh"
#include "nix/expr/get-drvs.hh"

#include "nix_api_expr.h"
#include "nix_api_expr_internal.h"
#include "nix_api_store.h"
#include "nix_api_store_internal.h"
#include "nix_api_util.h"
#include "nix_api_util_internal.h"

static const nix::Bindings & get_bindings_or_empty(nix::EvalState & state, nix_value * autoArgs)
{
if (!autoArgs) {
return nix::Bindings::emptyBindings;
}
auto & v = check_value_in(autoArgs);
state.forceAttrs(v, nix::noPos, "while evaluating automatic function arguments");
return *v.attrs();
}

extern "C" {

StorePath *
nix_get_derivation(nix_c_context * context, EvalState * state, nix_value * value, bool ignoreAssertionFailures)
{
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_in(value);
auto maybePkg = nix::getDerivation(state->state, v, ignoreAssertionFailures);
if (!maybePkg) {
return nullptr;
}
nix::StorePath sp = maybePkg->requireDrvPath();
return new StorePath{std::move(sp)};
}
NIXC_CATCH_ERRS_NULL
}

nix_err nix_value_auto_call_function(
nix_c_context * context, EvalState * state, nix_value * auto_args, nix_value * fn_val, nix_value * result)
{
if (context)
context->last_err_code = NIX_OK;
try {
auto & fn = check_value_in(fn_val);
auto & res = check_value_not_null(result);

auto & b = get_bindings_or_empty(state->state, auto_args);
state->state.autoCallFunction(b, fn, res);
}
NIXC_CATCH_ERRS
}

} // extern "C"
63 changes: 63 additions & 0 deletions src/libexpr-c/nix_api_expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,69 @@ void nix_gc_register_finalizer(void * obj, void * cd, void (*finalizer)(void * o

/** @} */ // doxygen group GC

/** @defgroup libexpr_eval Evaluation
* @ingroup libexpr
* @brief Higher-level evaluation helpers
* @{
*/

/**
* @brief Determine whether a Nix value is a derivation and, if so, return its
* store derivation path.
*
* Forces @p value and inspects it. The value is considered a derivation when it
* is an attribute set whose `type` attribute is the string `"derivation"`; in
* that case its `drvPath` attribute is parsed and returned. Otherwise NULL is
* returned without recording an error.
*
* Only the derivation path is returned. Other metadata (`name`, `system`,
* outputs, `meta`, ...) lives on @p value itself and can be read with the
* attribute-set accessors such as nix_get_attr_byname() and nix_get_string().
*
* @param[out] context Optional, stores error information. On a NULL return,
* inspect the error code via nix_err_code() to tell the two NULL cases apart:
* NIX_OK means @p value is simply not a derivation, any other code means
* inspection failed. See @ref errors.
* @param[in] state The evaluation state.
* @param[in] value The value to inspect. It is forced by this call.
* @param[in] ignoreAssertionFailures If true, an assertion failure raised while
* forcing @p value is treated as "not a derivation" (NULL is returned without
* an error) rather than being reported as an error.
* @return A newly allocated StorePath holding the derivation path, or NULL.
* Free a non-NULL result with nix_store_path_free().
*/
StorePath *
nix_get_derivation(nix_c_context * context, EvalState * state, nix_value * value, bool ignoreAssertionFailures);

/**
* @brief Call a function, drawing its arguments from an attribute set.
*
* Forces @p fn_val and writes the application result into @p result. The result
* is not forced; call nix_value_force() to evaluate it before inspecting the
* final value.
*
* - If @p fn_val is a function that takes a set of named arguments
* (e.g. `{ a, b ? 1 }: ...`), it is called with an attribute set assembled
* from @p auto_args: each named argument is taken from @p auto_args when
* present; an argument absent from @p auto_args falls back to its default;
* an argument that is both absent and has no default is an error.
* - Otherwise @p fn_val is copied into @p result unchanged. This includes any
* non-function value as well as a function that takes a single unnamed
* argument (e.g. `x: ...`), since there are no named arguments to supply.
*
* @param[out] context Optional, stores error information
* @param[in] state The evaluation state.
* @param[in] auto_args Attribute set value supplying the named arguments, or
* NULL to supply none.
* @param[in] fn_val The value to call.
* @param[out] result Pre-allocated nix_value that receives the result.
* @return NIX_OK if the call was successful, an error code otherwise.
*/
nix_err nix_value_auto_call_function(
nix_c_context * context, EvalState * state, nix_value * auto_args, nix_value * fn_val, nix_value * result);

/** @} */ // doxygen group libexpr_eval

// cffi end
#ifdef __cplusplus
}
Expand Down
32 changes: 32 additions & 0 deletions src/libexpr-c/nix_api_expr_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define NIX_API_EXPR_INTERNAL_H

#include <memory>
#include <stdexcept>

#include "nix/fetchers/fetch-settings.hh"
#include "nix/expr/eval.hh"
Expand Down Expand Up @@ -74,4 +75,35 @@ struct nix_realised_string

} // extern "C"

// Shared helpers for validating nix_value [in] parameters across libexpr-c translation units.
inline const nix::Value & check_value_not_null(const nix_value * value)
{
if (!value || !value->value)
throw std::runtime_error("nix_value is null");
return *value->value;
}

inline nix::Value & check_value_not_null(nix_value * value)
{
if (!value || !value->value)
throw std::runtime_error("nix_value is null");
return *value->value;
}

inline const nix::Value & check_value_in(const nix_value * value)
{
auto & v = check_value_not_null(value);
if (!v.isValid())
throw std::runtime_error("Uninitialized nix_value");
return v;
}

inline nix::Value & check_value_in(nix_value * value)
{
auto & v = check_value_not_null(value);
if (!v.isValid())
throw std::runtime_error("Uninitialized nix_value");
return v;
}

#endif // NIX_API_EXPR_INTERNAL_H
35 changes: 0 additions & 35 deletions src/libexpr-c/nix_api_value.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,41 +12,6 @@
#include "nix_api_store_internal.h"
#include "nix_api_value.h"

// Internal helper functions to check [in] and [out] `Value *` parameters
static const nix::Value & check_value_not_null(const nix_value * value)
{
if (!value) {
throw std::runtime_error("nix_value is null");
}
return *value->value;
}

static nix::Value & check_value_not_null(nix_value * value)
{
if (!value) {
throw std::runtime_error("nix_value is null");
}
return *value->value;
}

static const nix::Value & check_value_in(const nix_value * value)
{
auto & v = check_value_not_null(value);
if (!v.isValid()) {
throw std::runtime_error("Uninitialized nix_value");
}
return v;
}

static nix::Value & check_value_in(nix_value * value)
{
auto & v = check_value_not_null(value);
if (!v.isValid()) {
throw std::runtime_error("Uninitialized nix_value");
}
return v;
}

static nix::Value & check_value_out(nix_value * value)
{
auto & v = check_value_not_null(value);
Expand Down
1 change: 1 addition & 0 deletions src/libexpr-tests/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ sources = files(
'json.cc',
'lazy-fetcher-attr.cc',
'main.cc',
'nix_api_eval.cc',
'nix_api_expr.cc',
'nix_api_external.cc',
'nix_api_value.cc',
Expand Down
Loading
Loading