C API: rename State to EvalState

This commit is contained in:
José Luis Lafuente 2024-01-10 11:58:35 +01:00 committed by José Luis Lafuente
parent 24604d024a
commit 535694122e
No known key found for this signature in database
GPG Key ID: 8A3455EBE455489A
9 changed files with 85 additions and 64 deletions

View File

@ -1,30 +1,40 @@
# Getting started
> **Warning**
> These bindings are **experimental**, which means they can change at any time or be removed outright; nevertheless the plan is to provide a stable external C API to the Nix language and the Nix store.
> **Warning** These bindings are **experimental**, which means they can change
> at any time or be removed outright; nevertheless the plan is to provide a
> stable external C API to the Nix language and the Nix store.
The language library allows evaluating Nix expressions and interacting with Nix language values.
The Nix store API is still rudimentary, and only allows initialising and connecting to a store for the Nix language evaluator to interact with.
The language library allows evaluating Nix expressions and interacting with Nix
language values. The Nix store API is still rudimentary, and only allows
initialising and connecting to a store for the Nix language evaluator to
interact with.
Currently there are two ways to interface with the Nix language evaluator
programmatically:
Currently there are two ways to interface with the Nix language evaluator programmatically:
1. Embedding the evaluator
2. Writing language plug-ins
Embedding means you link the Nix C libraries in your program and use them from there.
Adding a plug-in means you make a library that gets loaded by the Nix language evaluator, specified through a configuration option.
Embedding means you link the Nix C libraries in your program and use them from
there. Adding a plug-in means you make a library that gets loaded by the Nix
language evaluator, specified through a configuration option.
Many of the components and mechanisms involved are not yet documented, therefore please refer to the [Nix source code](https://github.com/NixOS/nix/) for details.
Additions to in-code documentation and the reference manual are highly appreciated.
Many of the components and mechanisms involved are not yet documented, therefore
please refer to the [Nix source code](https://github.com/NixOS/nix/) for
details. Additions to in-code documentation and the reference manual are highly
appreciated.
The following examples, for simplicity, don't include error handling.
See the [Handling errors](@ref errors) section for more information.
The following examples, for simplicity, don't include error handling. See the
[Handling errors](@ref errors) section for more information.
# Embedding the Nix Evaluator
In this example we programmatically start the Nix language evaluator with a dummy store (that has no store paths and cannot be written to), and evaluate the Nix expression `builtins.nixVersion`.
In this example we programmatically start the Nix language evaluator with a
dummy store (that has no store paths and cannot be written to), and evaluate the
Nix expression `builtins.nixVersion`.
**main.c:**
```C
#include <nix_api_util.h>
#include <nix_api_expr.h>
@ -35,7 +45,7 @@ int main() {
nix_libexpr_init(NULL);
Store* store = nix_store_open(NULL, "dummy://", NULL);
State* state = nix_state_create(NULL, NULL, store); // empty search path (NIX_PATH)
EvalState* state = nix_state_create(NULL, NULL, store); // empty search path (NIX_PATH)
Value *value = nix_alloc_value(NULL, state);
nix_expr_eval_from_string(NULL, state, "builtins.nixVersion", ".", value);
@ -50,24 +60,26 @@ int main() {
```
**Usage:**
```ShellSession
$ gcc main.c $(pkg-config nix-expr-c --libs --cflags) -o main
$ ./main
Nix version: 2.17
```
# Writing a Nix language plug-in
In this example we add a custom primitive operation (*primop*) to `builtins`.
It will increment the argument if it is an integer and throw an error otherwise.
In this example we add a custom primitive operation (_primop_) to `builtins`. It
will increment the argument if it is an integer and throw an error otherwise.
**plugin.c:**
```C
#include <nix_api_util.h>
#include <nix_api_expr.h>
#include <nix_api_value.h>
void increment(void* user_data, nix_c_context* ctx, State* state, Value** args, Value* v) {
void increment(void* user_data, nix_c_context* ctx, EvalState* state, Value** args, Value* v) {
nix_value_force(NULL, state, args[0]);
if (nix_get_type(NULL, args[0]) == NIX_TYPE_INT) {
nix_set_int(NULL, v, nix_get_int(NULL, args[0]) + 1);
@ -85,6 +97,7 @@ void nix_plugin_entry() {
```
**Usage:**
```ShellSession
$ gcc plugin.c $(pkg-config nix-expr-c --libs --cflags) -shared -o plugin.so
$ nix --plugin-files ./plugin.so repl

View File

@ -41,8 +41,8 @@ nix_err nix_libexpr_init(nix_c_context * context)
NIXC_CATCH_ERRS
}
nix_err
nix_expr_eval_from_string(nix_c_context * context, State * state, const char * expr, const char * path, Value * value)
nix_err nix_expr_eval_from_string(
nix_c_context * context, EvalState * state, const char * expr, const char * path, Value * value)
{
if (context)
context->last_err_code = NIX_OK;
@ -54,7 +54,7 @@ nix_expr_eval_from_string(nix_c_context * context, State * state, const char * e
NIXC_CATCH_ERRS
}
nix_err nix_value_call(nix_c_context * context, State * state, Value * fn, Value * arg, Value * value)
nix_err nix_value_call(nix_c_context * context, EvalState * state, Value * fn, Value * arg, Value * value)
{
if (context)
context->last_err_code = NIX_OK;
@ -65,7 +65,7 @@ nix_err nix_value_call(nix_c_context * context, State * state, Value * fn, Value
NIXC_CATCH_ERRS
}
nix_err nix_value_force(nix_c_context * context, State * state, Value * value)
nix_err nix_value_force(nix_c_context * context, EvalState * state, Value * value)
{
if (context)
context->last_err_code = NIX_OK;
@ -75,7 +75,7 @@ nix_err nix_value_force(nix_c_context * context, State * state, Value * value)
NIXC_CATCH_ERRS
}
nix_err nix_value_force_deep(nix_c_context * context, State * state, Value * value)
nix_err nix_value_force_deep(nix_c_context * context, EvalState * state, Value * value)
{
if (context)
context->last_err_code = NIX_OK;
@ -85,7 +85,7 @@ nix_err nix_value_force_deep(nix_c_context * context, State * state, Value * val
NIXC_CATCH_ERRS
}
State * nix_state_create(nix_c_context * context, const char ** searchPath_c, Store * store)
EvalState * nix_state_create(nix_c_context * context, const char ** searchPath_c, Store * store)
{
if (context)
context->last_err_code = NIX_OK;
@ -95,12 +95,12 @@ State * nix_state_create(nix_c_context * context, const char ** searchPath_c, St
for (size_t i = 0; searchPath_c[i] != nullptr; i++)
searchPath.push_back(searchPath_c[i]);
return new State{nix::EvalState(nix::SearchPath::parse(searchPath), store->ptr)};
return new EvalState{nix::EvalState(nix::SearchPath::parse(searchPath), store->ptr)};
}
NIXC_CATCH_ERRS_NULL
}
void nix_state_free(State * state)
void nix_state_free(EvalState * state)
{
delete state;
}

View File

@ -9,7 +9,7 @@
* nix_libexpr_init(NULL);
*
* Store* store = nix_store_open(NULL, "dummy", NULL);
* State* state = nix_state_create(NULL, NULL, store); // empty nix path
* EvalState* state = nix_state_create(NULL, NULL, store); // empty nix path
* Value *value = nix_alloc_value(NULL, state);
*
* nix_expr_eval_from_string(NULL, state, "builtins.nixVersion", ".", value);
@ -42,10 +42,10 @@ extern "C" {
*
* Multiple states can be created for multi-threaded
* operation.
* @struct State
* @struct EvalState
* @see nix_state_create
*/
typedef struct State State; // nix::EvalState
typedef struct EvalState EvalState; // nix::EvalState
/**
* @brief Represents a value in the Nix language.
*
@ -60,7 +60,7 @@ typedef void Value; // nix::Value
* @brief Initialize the Nix language evaluator.
*
* This function must be called at least once,
* at some point before constructing a State for the first time.
* at some point before constructing a EvalState for the first time.
* This function can be called multiple times, and is idempotent.
*
* @param[out] context Optional, stores error information
@ -77,12 +77,12 @@ nix_err nix_libexpr_init(nix_c_context * context);
* @param[in] path The file path to associate with the expression.
* This is required for expressions that contain relative paths (such as `./.`) that are resolved relative to the given
* directory.
* @param[out] value The result of the evaluation. You should allocate this
* @param[out] value The result of the evaluation. You must allocate this
* yourself.
* @return NIX_OK if the evaluation was successful, an error code otherwise.
*/
nix_err
nix_expr_eval_from_string(nix_c_context * context, State * state, const char * expr, const char * path, Value * value);
nix_err nix_expr_eval_from_string(
nix_c_context * context, EvalState * state, const char * expr, const char * path, Value * value);
/**
* @brief Calls a Nix function with an argument.
@ -94,7 +94,7 @@ nix_expr_eval_from_string(nix_c_context * context, State * state, const char * e
* @param[out] value The result of the function call.
* @return NIX_OK if the function call was successful, an error code otherwise.
*/
nix_err nix_value_call(nix_c_context * context, State * state, Value * fn, Value * arg, Value * value);
nix_err nix_value_call(nix_c_context * context, EvalState * state, Value * fn, Value * arg, Value * value);
/**
* @brief Forces the evaluation of a Nix value.
@ -116,7 +116,7 @@ nix_err nix_value_call(nix_c_context * context, State * state, Value * fn, Value
* @return NIX_OK if the force operation was successful, an error code
* otherwise.
*/
nix_err nix_value_force(nix_c_context * context, State * state, Value * value);
nix_err nix_value_force(nix_c_context * context, EvalState * state, Value * value);
/**
* @brief Forces the deep evaluation of a Nix value.
@ -132,7 +132,7 @@ nix_err nix_value_force(nix_c_context * context, State * state, Value * value);
* @return NIX_OK if the deep force operation was successful, an error code
* otherwise.
*/
nix_err nix_value_force_deep(nix_c_context * context, State * state, Value * value);
nix_err nix_value_force_deep(nix_c_context * context, EvalState * state, Value * value);
/**
* @brief Create a new Nix language evaluator state.
@ -142,7 +142,7 @@ nix_err nix_value_force_deep(nix_c_context * context, State * state, Value * val
* @param[in] store The Nix store to use.
* @return A new Nix state or NULL on failure.
*/
State * nix_state_create(nix_c_context * context, const char ** searchPath, Store * store);
EvalState * nix_state_create(nix_c_context * context, const char ** searchPath, Store * store);
/**
* @brief Frees a Nix state.
@ -151,7 +151,7 @@ State * nix_state_create(nix_c_context * context, const char ** searchPath, Stor
*
* @param[in] state The state to free.
*/
void nix_state_free(State * state);
void nix_state_free(EvalState * state);
/** @addtogroup GC
* @brief Reference counting and garbage collector operations

View File

@ -4,7 +4,7 @@
#include "eval.hh"
#include "attr-set.hh"
struct State
struct EvalState
{
nix::EvalState state;
};

View File

@ -148,7 +148,7 @@ public:
}
nix_string_context ctx{context};
nix_string_return res{""};
desc.printValueAsJSON(v, (State *) &state, strict, &ctx, copyToStore, &res);
desc.printValueAsJSON(v, (EvalState *) &state, strict, &ctx, copyToStore, &res);
if (res.str.empty()) {
return nix::ExternalValueBase::printValueAsJSON(state, strict, context, copyToStore);
}
@ -172,7 +172,8 @@ public:
}
nix_string_context ctx{context};
desc.printValueAsXML(
v, (State *) &state, strict, location, &doc, &ctx, &drvsSeen, *reinterpret_cast<const uint32_t *>(&pos));
v, (EvalState *) &state, strict, location, &doc, &ctx, &drvsSeen,
*reinterpret_cast<const uint32_t *>(&pos));
}
virtual ~NixCExternalValue() override{};

View File

@ -136,7 +136,7 @@ typedef struct NixCExternalValueDesc
* or setting it to the empty string, will make the conversion throw an error.
*/
void (*printValueAsJSON)(
void * self, State *, int strict, nix_string_context * c, bool copyToStore, nix_string_return * res);
void * self, EvalState *, int strict, nix_string_context * c, bool copyToStore, nix_string_return * res);
/**
* @brief Convert the external value to XML
*
@ -154,7 +154,14 @@ typedef struct NixCExternalValueDesc
* @param[in] pos The position of the call.
*/
void (*printValueAsXML)(
void * self, State *, int strict, int location, void * doc, nix_string_context * c, void * drvsSeen, int pos);
void * self,
EvalState *,
int strict,
int location,
void * doc,
nix_string_context * c,
void * drvsSeen,
int pos);
} NixCExternalValueDesc;
/**

View File

@ -43,7 +43,7 @@ static void nix_c_primop_wrapper(
PrimOpFun f, void * userdata, nix::EvalState & state, const nix::PosIdx pos, nix::Value ** args, nix::Value & v)
{
nix_c_context ctx;
f(userdata, &ctx, (State *) &state, (Value **) args, (Value *) &v);
f(userdata, &ctx, (EvalState *) &state, (Value **) args, (Value *) &v);
/* TODO: In the future, this should throw different errors depending on the error code */
if (ctx.last_err_code != NIX_OK)
state.debugThrowLastTrace(nix::Error(
@ -92,7 +92,7 @@ nix_err nix_register_primop(nix_c_context * context, PrimOp * primOp)
NIXC_CATCH_ERRS
}
Value * nix_alloc_value(nix_c_context * context, State * state)
Value * nix_alloc_value(nix_c_context * context, EvalState * state)
{
if (context)
context->last_err_code = NIX_OK;
@ -255,7 +255,7 @@ ExternalValue * nix_get_external(nix_c_context * context, Value * value)
NIXC_CATCH_ERRS_NULL;
}
Value * nix_get_list_byidx(nix_c_context * context, const Value * value, State * state, unsigned int ix)
Value * nix_get_list_byidx(nix_c_context * context, const Value * value, EvalState * state, unsigned int ix)
{
if (context)
context->last_err_code = NIX_OK;
@ -270,7 +270,7 @@ Value * nix_get_list_byidx(nix_c_context * context, const Value * value, State *
NIXC_CATCH_ERRS_NULL
}
Value * nix_get_attr_byname(nix_c_context * context, const Value * value, State * state, const char * name)
Value * nix_get_attr_byname(nix_c_context * context, const Value * value, EvalState * state, const char * name)
{
if (context)
context->last_err_code = NIX_OK;
@ -290,7 +290,7 @@ Value * nix_get_attr_byname(nix_c_context * context, const Value * value, State
NIXC_CATCH_ERRS_NULL
}
bool nix_has_attr_byname(nix_c_context * context, const Value * value, State * state, const char * name)
bool nix_has_attr_byname(nix_c_context * context, const Value * value, EvalState * state, const char * name)
{
if (context)
context->last_err_code = NIX_OK;
@ -307,7 +307,7 @@ bool nix_has_attr_byname(nix_c_context * context, const Value * value, State * s
}
Value *
nix_get_attr_byidx(nix_c_context * context, const Value * value, State * state, unsigned int i, const char ** name)
nix_get_attr_byidx(nix_c_context * context, const Value * value, EvalState * state, unsigned int i, const char ** name)
{
if (context)
context->last_err_code = NIX_OK;
@ -322,7 +322,7 @@ nix_get_attr_byidx(nix_c_context * context, const Value * value, State * state,
NIXC_CATCH_ERRS_NULL
}
const char * nix_get_attr_name_byidx(nix_c_context * context, const Value * value, State * state, unsigned int i)
const char * nix_get_attr_name_byidx(nix_c_context * context, const Value * value, EvalState * state, unsigned int i)
{
if (context)
context->last_err_code = NIX_OK;
@ -413,7 +413,7 @@ nix_err nix_set_external(nix_c_context * context, Value * value, ExternalValue *
NIXC_CATCH_ERRS
}
nix_err nix_make_list(nix_c_context * context, State * s, Value * value, unsigned int size)
nix_err nix_make_list(nix_c_context * context, EvalState * s, Value * value, unsigned int size)
{
if (context)
context->last_err_code = NIX_OK;
@ -471,7 +471,7 @@ nix_err nix_make_attrs(nix_c_context * context, Value * value, BindingsBuilder *
NIXC_CATCH_ERRS
}
BindingsBuilder * nix_make_bindings_builder(nix_c_context * context, State * state, size_t capacity)
BindingsBuilder * nix_make_bindings_builder(nix_c_context * context, EvalState * state, size_t capacity)
{
if (context)
context->last_err_code = NIX_OK;

View File

@ -35,7 +35,7 @@ typedef enum {
// forward declarations
typedef void Value;
typedef struct State State;
typedef struct EvalState EvalState;
// type defs
/** @brief Stores an under-construction set of bindings
* @ingroup value_manip
@ -75,7 +75,7 @@ typedef struct ExternalValue ExternalValue;
* @param[out] ret return value
* @see nix_alloc_primop, nix_set_primop
*/
typedef void (*PrimOpFun)(void * user_data, nix_c_context * context, State * state, Value ** args, Value * ret);
typedef void (*PrimOpFun)(void * user_data, nix_c_context * context, EvalState * state, Value ** args, Value * ret);
/** @brief Allocate a PrimOp
*
@ -127,7 +127,7 @@ nix_err nix_register_primop(nix_c_context * context, PrimOp * primOp);
* @return value, or null in case of errors
*
*/
Value * nix_alloc_value(nix_c_context * context, State * state);
Value * nix_alloc_value(nix_c_context * context, EvalState * state);
/** @addtogroup value_manip Manipulating values
* @brief Functions to inspect and change Nix language values, represented by Value.
* @{
@ -209,7 +209,7 @@ ExternalValue * nix_get_external(nix_c_context * context, Value *);
* @param[in] ix list element to get
* @return value, NULL in case of errors
*/
Value * nix_get_list_byidx(nix_c_context * context, const Value * value, State * state, unsigned int ix);
Value * nix_get_list_byidx(nix_c_context * context, const Value * value, EvalState * state, unsigned int ix);
/** @brief Get an attr by name
*
* Owned by the GC. Use nix_gc_decref when you're done with the pointer
@ -219,7 +219,7 @@ Value * nix_get_list_byidx(nix_c_context * context, const Value * value, State *
* @param[in] name attribute name
* @return value, NULL in case of errors
*/
Value * nix_get_attr_byname(nix_c_context * context, const Value * value, State * state, const char * name);
Value * nix_get_attr_byname(nix_c_context * context, const Value * value, EvalState * state, const char * name);
/** @brief Check if an attribute name exists on a value
* @param[out] context Optional, stores error information
@ -228,7 +228,7 @@ Value * nix_get_attr_byname(nix_c_context * context, const Value * value, State
* @param[in] name attribute name
* @return value, error info via context
*/
bool nix_has_attr_byname(nix_c_context * context, const Value * value, State * state, const char * name);
bool nix_has_attr_byname(nix_c_context * context, const Value * value, EvalState * state, const char * name);
/** @brief Get an attribute by index in the sorted bindings
*
@ -243,20 +243,20 @@ bool nix_has_attr_byname(nix_c_context * context, const Value * value, State * s
* @return value, NULL in case of errors
*/
Value *
nix_get_attr_byidx(nix_c_context * context, const Value * value, State * state, unsigned int i, const char ** name);
nix_get_attr_byidx(nix_c_context * context, const Value * value, EvalState * state, unsigned int i, const char ** name);
/** @brief Get an attribute name by index in the sorted bindings
*
* Useful when you want the name but want to avoid evaluation.
*
* Owned by the nix State
* Owned by the nix EvalState
* @param[out] context Optional, stores error information
* @param[in] value Nix value to inspect
* @param[in] state nix evaluator state
* @param[in] i attribute index
* @return name, NULL in case of errors
*/
const char * nix_get_attr_name_byidx(nix_c_context * context, const Value * value, State * state, unsigned int i);
const char * nix_get_attr_name_byidx(nix_c_context * context, const Value * value, EvalState * state, unsigned int i);
/**@}*/
/** @name Setters
*/
@ -315,7 +315,7 @@ nix_err nix_set_external(nix_c_context * context, Value * value, ExternalValue *
* @param[in] size size of list
* @return error code, NIX_OK on success.
*/
nix_err nix_make_list(nix_c_context * context, State * s, Value * value, unsigned int size);
nix_err nix_make_list(nix_c_context * context, EvalState * s, Value * value, unsigned int size);
/** @brief Manipulate a list by index
*
* Don't do this mid-computation.
@ -359,7 +359,7 @@ nix_err nix_copy_value(nix_c_context * context, Value * value, Value * source);
* @return owned reference to a bindings builder. Make sure to unref when you're
done.
*/
BindingsBuilder * nix_make_bindings_builder(nix_c_context * context, State * state, size_t capacity);
BindingsBuilder * nix_make_bindings_builder(nix_c_context * context, EvalState * state, size_t capacity);
/** @brief Insert bindings into a builder
* @param[out] context Optional, stores error information
* @param[in] builder BindingsBuilder to insert into

View File

@ -25,7 +25,7 @@ public:
nix_state_free(state);
}
State * state;
EvalState * state;
Value * value;
};