C API: add check_value_[in,out] helper functions

This commit is contained in:
José Luis Lafuente 2024-04-21 22:13:26 +02:00
parent ff76dd2211
commit 8d70db3251
No known key found for this signature in database
GPG key ID: 8A3455EBE455489A
2 changed files with 54 additions and 64 deletions

View file

@ -20,7 +20,7 @@
# include "gc_cpp.h" # include "gc_cpp.h"
#endif #endif
// Helper function to throw an exception if value is null or in an invalid state // Internal helper functions to check [in] and [out] `Value *` parameters
static const nix::Value & check_value_not_null(const Value * value) static const nix::Value & check_value_not_null(const Value * value)
{ {
if (!value) { if (!value) {
@ -37,18 +37,31 @@ static nix::Value & check_value_not_null(Value * value)
return *((nix::Value *) value); return *((nix::Value *) value);
} }
static void check_value_initialized(const nix::Value & value) static const nix::Value & check_value_in(const Value * value)
{ {
if (!value.isValid()) { auto & v = check_value_not_null(value);
if (!v.isValid()) {
throw std::runtime_error("Uninitialized Value"); throw std::runtime_error("Uninitialized Value");
} }
return v;
} }
static void check_value_uninitialized(const nix::Value & value) static nix::Value & check_value_in(Value * value)
{ {
if (value.isValid()) { auto & v = check_value_not_null(value);
if (!v.isValid()) {
throw std::runtime_error("Uninitialized Value");
}
return v;
}
static nix::Value & check_value_out(Value * value)
{
auto & v = check_value_not_null(value);
if (v.isValid()) {
throw std::runtime_error("Value already initialized. Variables are immutable"); throw std::runtime_error("Value already initialized. Variables are immutable");
} }
return v;
} }
/** /**
@ -125,8 +138,7 @@ ValueType nix_get_type(nix_c_context * context, const Value * value)
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & v = check_value_not_null(value); auto & v = check_value_in(value);
check_value_initialized(v);
using namespace nix; using namespace nix;
switch (v.type()) { switch (v.type()) {
case nThunk: case nThunk:
@ -162,8 +174,7 @@ const char * nix_get_typename(nix_c_context * context, const Value * value)
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & v = check_value_not_null(value); auto & v = check_value_in(value);
check_value_initialized(v);
auto s = nix::showType(v); auto s = nix::showType(v);
return strdup(s.c_str()); return strdup(s.c_str());
} }
@ -175,8 +186,7 @@ bool nix_get_bool(nix_c_context * context, const Value * value)
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & v = check_value_not_null(value); auto & v = check_value_in(value);
check_value_initialized(v);
assert(v.type() == nix::nBool); assert(v.type() == nix::nBool);
return v.boolean(); return v.boolean();
} }
@ -188,8 +198,7 @@ nix_err nix_get_string(nix_c_context * context, const Value * value, nix_get_str
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & v = check_value_not_null(value); auto & v = check_value_in(value);
check_value_initialized(v);
assert(v.type() == nix::nString); assert(v.type() == nix::nString);
call_nix_get_string_callback(v.c_str(), callback, user_data); call_nix_get_string_callback(v.c_str(), callback, user_data);
} }
@ -201,8 +210,7 @@ const char * nix_get_path_string(nix_c_context * context, const Value * value)
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & v = check_value_not_null(value); auto & v = check_value_in(value);
check_value_initialized(v);
assert(v.type() == nix::nPath); assert(v.type() == nix::nPath);
// NOTE (from @yorickvP) // NOTE (from @yorickvP)
// v._path.path should work but may not be how Eelco intended it. // v._path.path should work but may not be how Eelco intended it.
@ -221,8 +229,7 @@ unsigned int nix_get_list_size(nix_c_context * context, const Value * value)
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & v = check_value_not_null(value); auto & v = check_value_in(value);
check_value_initialized(v);
assert(v.type() == nix::nList); assert(v.type() == nix::nList);
return v.listSize(); return v.listSize();
} }
@ -234,8 +241,7 @@ unsigned int nix_get_attrs_size(nix_c_context * context, const Value * value)
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & v = check_value_not_null(value); auto & v = check_value_in(value);
check_value_initialized(v);
assert(v.type() == nix::nAttrs); assert(v.type() == nix::nAttrs);
return v.attrs()->size(); return v.attrs()->size();
} }
@ -247,8 +253,7 @@ double nix_get_float(nix_c_context * context, const Value * value)
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & v = check_value_not_null(value); auto & v = check_value_in(value);
check_value_initialized(v);
assert(v.type() == nix::nFloat); assert(v.type() == nix::nFloat);
return v.fpoint(); return v.fpoint();
} }
@ -260,8 +265,7 @@ int64_t nix_get_int(nix_c_context * context, const Value * value)
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & v = check_value_not_null(value); auto & v = check_value_in(value);
check_value_initialized(v);
assert(v.type() == nix::nInt); assert(v.type() == nix::nInt);
return v.integer(); return v.integer();
} }
@ -273,8 +277,7 @@ ExternalValue * nix_get_external(nix_c_context * context, Value * value)
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & v = check_value_not_null(value); auto & v = check_value_out(value);
check_value_initialized(v);
assert(v.type() == nix::nExternal); assert(v.type() == nix::nExternal);
return (ExternalValue *) v.external(); return (ExternalValue *) v.external();
} }
@ -286,8 +289,7 @@ Value * nix_get_list_byidx(nix_c_context * context, const Value * value, EvalSta
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & v = check_value_not_null(value); auto & v = check_value_in(value);
check_value_initialized(v);
assert(v.type() == nix::nList); assert(v.type() == nix::nList);
auto * p = v.listElems()[ix]; auto * p = v.listElems()[ix];
nix_gc_incref(nullptr, p); nix_gc_incref(nullptr, p);
@ -303,8 +305,7 @@ Value * nix_get_attr_byname(nix_c_context * context, const Value * value, EvalSt
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & v = check_value_not_null(value); auto & v = check_value_in(value);
check_value_initialized(v);
assert(v.type() == nix::nAttrs); assert(v.type() == nix::nAttrs);
nix::Symbol s = state->state.symbols.create(name); nix::Symbol s = state->state.symbols.create(name);
auto attr = v.attrs()->get(s); auto attr = v.attrs()->get(s);
@ -324,8 +325,7 @@ bool nix_has_attr_byname(nix_c_context * context, const Value * value, EvalState
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & v = check_value_not_null(value); auto & v = check_value_in(value);
check_value_initialized(v);
assert(v.type() == nix::nAttrs); assert(v.type() == nix::nAttrs);
nix::Symbol s = state->state.symbols.create(name); nix::Symbol s = state->state.symbols.create(name);
auto attr = v.attrs()->get(s); auto attr = v.attrs()->get(s);
@ -342,8 +342,7 @@ nix_get_attr_byidx(nix_c_context * context, const Value * value, EvalState * sta
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & v = check_value_not_null(value); auto & v = check_value_in(value);
check_value_initialized(v);
const nix::Attr & a = (*v.attrs())[i]; const nix::Attr & a = (*v.attrs())[i];
*name = ((const std::string &) (state->state.symbols[a.name])).c_str(); *name = ((const std::string &) (state->state.symbols[a.name])).c_str();
nix_gc_incref(nullptr, a.value); nix_gc_incref(nullptr, a.value);
@ -358,8 +357,7 @@ const char * nix_get_attr_name_byidx(nix_c_context * context, const Value * valu
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & v = check_value_not_null(value); auto & v = check_value_in(value);
check_value_initialized(v);
const nix::Attr & a = (*v.attrs())[i]; const nix::Attr & a = (*v.attrs())[i];
return ((const std::string &) (state->state.symbols[a.name])).c_str(); return ((const std::string &) (state->state.symbols[a.name])).c_str();
} }
@ -371,8 +369,7 @@ nix_err nix_init_bool(nix_c_context * context, Value * value, bool b)
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & v = check_value_not_null(value); auto & v = check_value_out(value);
check_value_uninitialized(v);
v.mkBool(b); v.mkBool(b);
} }
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
@ -384,8 +381,7 @@ nix_err nix_init_string(nix_c_context * context, Value * value, const char * str
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & v = check_value_not_null(value); auto & v = check_value_out(value);
check_value_uninitialized(v);
v.mkString(std::string_view(str)); v.mkString(std::string_view(str));
} }
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
@ -396,8 +392,7 @@ nix_err nix_init_path_string(nix_c_context * context, EvalState * s, Value * val
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & v = check_value_not_null(value); auto & v = check_value_out(value);
check_value_uninitialized(v);
v.mkPath(s->state.rootPath(nix::CanonPath(str))); v.mkPath(s->state.rootPath(nix::CanonPath(str)));
} }
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
@ -408,8 +403,7 @@ nix_err nix_init_float(nix_c_context * context, Value * value, double d)
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & v = check_value_not_null(value); auto & v = check_value_out(value);
check_value_uninitialized(v);
v.mkFloat(d); v.mkFloat(d);
} }
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
@ -420,8 +414,7 @@ nix_err nix_init_int(nix_c_context * context, Value * value, int64_t i)
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & v = check_value_not_null(value); auto & v = check_value_out(value);
check_value_uninitialized(v);
v.mkInt(i); v.mkInt(i);
} }
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
@ -432,8 +425,7 @@ nix_err nix_init_null(nix_c_context * context, Value * value)
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & v = check_value_not_null(value); auto & v = check_value_out(value);
check_value_uninitialized(v);
v.mkNull(); v.mkNull();
} }
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
@ -457,8 +449,7 @@ nix_err nix_init_external(nix_c_context * context, Value * value, ExternalValue
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & v = check_value_not_null(value); auto & v = check_value_out(value);
check_value_uninitialized(v);
auto r = (nix::ExternalValueBase *) val; auto r = (nix::ExternalValueBase *) val;
v.mkExternal(r); v.mkExternal(r);
} }
@ -486,7 +477,6 @@ nix_err nix_list_builder_insert(nix_c_context * context, ListBuilder * list_buil
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & e = check_value_not_null(value); auto & e = check_value_not_null(value);
check_value_initialized(e);
list_builder->builder[index] = &e; list_builder->builder[index] = &e;
} }
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
@ -506,8 +496,7 @@ nix_err nix_make_list(nix_c_context * context, ListBuilder * list_builder, Value
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & v = check_value_not_null(value); auto & v = check_value_out(value);
check_value_uninitialized(v);
v.mkList(list_builder->builder); v.mkList(list_builder->builder);
} }
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
@ -518,8 +507,7 @@ nix_err nix_init_primop(nix_c_context * context, Value * value, PrimOp * p)
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & v = check_value_not_null(value); auto & v = check_value_out(value);
check_value_uninitialized(v);
v.mkPrimOp((nix::PrimOp *) p); v.mkPrimOp((nix::PrimOp *) p);
} }
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
@ -530,10 +518,8 @@ nix_err nix_copy_value(nix_c_context * context, Value * value, Value * source)
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & v = check_value_not_null(value); auto & v = check_value_out(value);
check_value_uninitialized(v); auto & s = check_value_in(source);
auto & s = check_value_not_null(source);
check_value_initialized(s);
v = s; v = s;
} }
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
@ -544,8 +530,7 @@ nix_err nix_make_attrs(nix_c_context * context, Value * value, BindingsBuilder *
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & v = check_value_not_null(value); auto & v = check_value_out(value);
check_value_uninitialized(v);
v.mkAttrs(b->builder); v.mkAttrs(b->builder);
} }
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
@ -572,7 +557,6 @@ nix_err nix_bindings_builder_insert(nix_c_context * context, BindingsBuilder * b
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & v = check_value_not_null(value); auto & v = check_value_not_null(value);
check_value_initialized(v);
nix::Symbol s = bb->builder.state.symbols.create(name); nix::Symbol s = bb->builder.state.symbols.create(name);
bb->builder.insert(s, &v); bb->builder.insert(s, &v);
} }
@ -593,8 +577,7 @@ nix_realised_string * nix_string_realise(nix_c_context * context, EvalState * st
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
auto & v = check_value_not_null(value); auto & v = check_value_in(value);
check_value_initialized(v);
nix::NixStringContext stringContext; nix::NixStringContext stringContext;
auto rawStr = state->state.coerceToString(nix::noPos, v, stringContext, "while realising a string").toOwned(); auto rawStr = state->state.coerceToString(nix::noPos, v, stringContext, "while realising a string").toOwned();
nix::StorePathSet storePaths; nix::StorePathSet storePaths;

View file

@ -139,13 +139,20 @@ TEST_F(nix_api_expr_test, nix_build_and_init_list)
ListBuilder * builder = nix_make_list_builder(ctx, state, size); ListBuilder * builder = nix_make_list_builder(ctx, state, size);
Value * intValue = nix_alloc_value(ctx, state); Value * intValue = nix_alloc_value(ctx, state);
Value * intValue2 = nix_alloc_value(ctx, state);
// `init` and `insert` can be called in any order
nix_init_int(ctx, intValue, 42); nix_init_int(ctx, intValue, 42);
nix_list_builder_insert(ctx, builder, 0, intValue); nix_list_builder_insert(ctx, builder, 0, intValue);
nix_list_builder_insert(ctx, builder, 1, intValue2);
nix_init_int(ctx, intValue2, 43);
nix_make_list(ctx, builder, value); nix_make_list(ctx, builder, value);
nix_list_builder_free(builder); nix_list_builder_free(builder);
ASSERT_EQ(42, nix_get_int(ctx, nix_get_list_byidx(ctx, value, state, 0))); ASSERT_EQ(42, nix_get_int(ctx, nix_get_list_byidx(ctx, value, state, 0)));
ASSERT_EQ(nullptr, nix_get_list_byidx(ctx, value, state, 1)); ASSERT_EQ(43, nix_get_int(ctx, nix_get_list_byidx(ctx, value, state, 1)));
ASSERT_EQ(nullptr, nix_get_list_byidx(ctx, value, state, 2));
ASSERT_EQ(10, nix_get_list_size(ctx, value)); ASSERT_EQ(10, nix_get_list_size(ctx, value));
ASSERT_STREQ("a list", nix_get_typename(ctx, value)); ASSERT_STREQ("a list", nix_get_typename(ctx, value));