Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
61 changes: 61 additions & 0 deletions src/libexpr-c/nix_api_eval.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#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_null(nix_value * autoArgs)
{
if (!autoArgs) {
return nullptr;
}
auto & v = check_value_in(autoArgs);
if (v.type() == nix::nAttrs) {
return v.attrs();
}
Comment thread
NotAShelf marked this conversation as resolved.
Outdated
return nullptr;
}

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 = *result->value;

const nix::Bindings * b = get_bindings_or_null(auto_args);
Comment thread
NotAShelf marked this conversation as resolved.
Outdated
if (b) {
state->state.autoCallFunction(*b, fn, res);
} else {
state->state.autoCallFunction(nix::Bindings::emptyBindings, fn, res);
}
}
NIXC_CATCH_ERRS
}

} // extern "C"
62 changes: 62 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,68 @@ 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, which signals that the caller should
* treat @p value as an ordinary attribute set (e.g. recurse into it).
*
* 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 its application into @p result:
*
* - 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