Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add isValid to nix::Value #10555

Merged
merged 6 commits into from
May 1, 2024
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
87 changes: 57 additions & 30 deletions src/libexpr-c/nix_api_value.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
# include "gc_cpp.h"
#endif

// Helper function to throw an exception if value is null
// Internal helper functions to check [in] and [out] `Value *` parameters
static const nix::Value & check_value_not_null(const Value * value)
{
if (!value) {
Expand All @@ -37,6 +37,33 @@ static nix::Value & check_value_not_null(Value * value)
return *((nix::Value *) value);
}

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

static nix::Value & check_value_in(Value * value)
{
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");
}
return v;
}

/**
* Helper function to convert calls from nix into C API.
*
Expand Down Expand Up @@ -111,7 +138,7 @@ ValueType nix_get_type(nix_c_context * context, const Value * value)
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_not_null(value);
auto & v = check_value_in(value);
using namespace nix;
switch (v.type()) {
case nThunk:
Expand Down Expand Up @@ -147,7 +174,7 @@ const char * nix_get_typename(nix_c_context * context, const Value * value)
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_not_null(value);
auto & v = check_value_in(value);
auto s = nix::showType(v);
return strdup(s.c_str());
}
Expand All @@ -159,7 +186,7 @@ bool nix_get_bool(nix_c_context * context, const Value * value)
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_not_null(value);
auto & v = check_value_in(value);
assert(v.type() == nix::nBool);
return v.boolean();
}
Expand All @@ -171,7 +198,7 @@ nix_err nix_get_string(nix_c_context * context, const Value * value, nix_get_str
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_not_null(value);
auto & v = check_value_in(value);
assert(v.type() == nix::nString);
call_nix_get_string_callback(v.c_str(), callback, user_data);
}
Expand All @@ -183,7 +210,7 @@ const char * nix_get_path_string(nix_c_context * context, const Value * value)
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_not_null(value);
auto & v = check_value_in(value);
assert(v.type() == nix::nPath);
// NOTE (from @yorickvP)
// v._path.path should work but may not be how Eelco intended it.
Expand All @@ -202,7 +229,7 @@ unsigned int nix_get_list_size(nix_c_context * context, const Value * value)
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_not_null(value);
auto & v = check_value_in(value);
assert(v.type() == nix::nList);
return v.listSize();
}
Expand All @@ -214,7 +241,7 @@ unsigned int nix_get_attrs_size(nix_c_context * context, const Value * value)
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_not_null(value);
auto & v = check_value_in(value);
assert(v.type() == nix::nAttrs);
return v.attrs()->size();
}
Expand All @@ -226,7 +253,7 @@ double nix_get_float(nix_c_context * context, const Value * value)
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_not_null(value);
auto & v = check_value_in(value);
assert(v.type() == nix::nFloat);
return v.fpoint();
}
Expand All @@ -238,7 +265,7 @@ int64_t nix_get_int(nix_c_context * context, const Value * value)
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_not_null(value);
auto & v = check_value_in(value);
assert(v.type() == nix::nInt);
return v.integer();
}
Expand All @@ -250,7 +277,7 @@ ExternalValue * nix_get_external(nix_c_context * context, Value * value)
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_not_null(value);
auto & v = check_value_out(value);
assert(v.type() == nix::nExternal);
return (ExternalValue *) v.external();
}
Expand All @@ -262,7 +289,7 @@ Value * nix_get_list_byidx(nix_c_context * context, const Value * value, EvalSta
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_not_null(value);
auto & v = check_value_in(value);
assert(v.type() == nix::nList);
auto * p = v.listElems()[ix];
nix_gc_incref(nullptr, p);
Expand All @@ -278,7 +305,7 @@ Value * nix_get_attr_byname(nix_c_context * context, const Value * value, EvalSt
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_not_null(value);
auto & v = check_value_in(value);
assert(v.type() == nix::nAttrs);
nix::Symbol s = state->state.symbols.create(name);
auto attr = v.attrs()->get(s);
Expand All @@ -298,7 +325,7 @@ bool nix_has_attr_byname(nix_c_context * context, const Value * value, EvalState
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_not_null(value);
auto & v = check_value_in(value);
assert(v.type() == nix::nAttrs);
nix::Symbol s = state->state.symbols.create(name);
auto attr = v.attrs()->get(s);
Expand All @@ -315,7 +342,7 @@ nix_get_attr_byidx(nix_c_context * context, const Value * value, EvalState * sta
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_not_null(value);
auto & v = check_value_in(value);
const nix::Attr & a = (*v.attrs())[i];
*name = ((const std::string &) (state->state.symbols[a.name])).c_str();
nix_gc_incref(nullptr, a.value);
Expand All @@ -330,7 +357,7 @@ const char * nix_get_attr_name_byidx(nix_c_context * context, const Value * valu
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_not_null(value);
auto & v = check_value_in(value);
const nix::Attr & a = (*v.attrs())[i];
return ((const std::string &) (state->state.symbols[a.name])).c_str();
}
Expand All @@ -342,7 +369,7 @@ nix_err nix_init_bool(nix_c_context * context, Value * value, bool b)
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_not_null(value);
auto & v = check_value_out(value);
v.mkBool(b);
}
NIXC_CATCH_ERRS
Expand All @@ -354,7 +381,7 @@ nix_err nix_init_string(nix_c_context * context, Value * value, const char * str
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_not_null(value);
auto & v = check_value_out(value);
v.mkString(std::string_view(str));
}
NIXC_CATCH_ERRS
Expand All @@ -365,7 +392,7 @@ nix_err nix_init_path_string(nix_c_context * context, EvalState * s, Value * val
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_not_null(value);
auto & v = check_value_out(value);
v.mkPath(s->state.rootPath(nix::CanonPath(str)));
}
NIXC_CATCH_ERRS
Expand All @@ -376,7 +403,7 @@ nix_err nix_init_float(nix_c_context * context, Value * value, double d)
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_not_null(value);
auto & v = check_value_out(value);
v.mkFloat(d);
}
NIXC_CATCH_ERRS
Expand All @@ -387,7 +414,7 @@ nix_err nix_init_int(nix_c_context * context, Value * value, int64_t i)
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_not_null(value);
auto & v = check_value_out(value);
v.mkInt(i);
}
NIXC_CATCH_ERRS
Expand All @@ -398,7 +425,7 @@ nix_err nix_init_null(nix_c_context * context, Value * value)
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_not_null(value);
auto & v = check_value_out(value);
v.mkNull();
}
NIXC_CATCH_ERRS
Expand All @@ -422,7 +449,7 @@ nix_err nix_init_external(nix_c_context * context, Value * value, ExternalValue
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_not_null(value);
auto & v = check_value_out(value);
auto r = (nix::ExternalValueBase *) val;
v.mkExternal(r);
}
Expand Down Expand Up @@ -469,7 +496,7 @@ nix_err nix_make_list(nix_c_context * context, ListBuilder * list_builder, Value
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_not_null(value);
auto & v = check_value_out(value);
v.mkList(list_builder->builder);
}
NIXC_CATCH_ERRS
Expand All @@ -480,19 +507,19 @@ nix_err nix_init_primop(nix_c_context * context, Value * value, PrimOp * p)
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_not_null(value);
auto & v = check_value_out(value);
v.mkPrimOp((nix::PrimOp *) p);
}
NIXC_CATCH_ERRS
}

nix_err nix_copy_value(nix_c_context * context, Value * value, Value * source)
nix_err nix_copy_value(nix_c_context * context, Value * value, const Value * source)
{
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_not_null(value);
auto & s = check_value_not_null(source);
auto & v = check_value_out(value);
auto & s = check_value_in(source);
v = s;
}
NIXC_CATCH_ERRS
Expand All @@ -503,7 +530,7 @@ nix_err nix_make_attrs(nix_c_context * context, Value * value, BindingsBuilder *
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_not_null(value);
auto & v = check_value_out(value);
v.mkAttrs(b->builder);
}
NIXC_CATCH_ERRS
Expand Down Expand Up @@ -550,7 +577,7 @@ nix_realised_string * nix_string_realise(nix_c_context * context, EvalState * st
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_not_null(value);
auto & v = check_value_in(value);
nix::NixStringContext stringContext;
auto rawStr = state->state.coerceToString(nix::noPos, v, stringContext, "while realising a string").toOwned();
nix::StorePathSet storePaths;
Expand Down
2 changes: 1 addition & 1 deletion src/libexpr-c/nix_api_value.h
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ nix_err nix_init_primop(nix_c_context * context, Value * value, PrimOp * op);
* @param[in] source value to copy from
* @return error code, NIX_OK on success.
*/
nix_err nix_copy_value(nix_c_context * context, Value * value, Value * source);
nix_err nix_copy_value(nix_c_context * context, Value * value, const Value * source);
/**@}*/

/** @brief Create a bindings builder
Expand Down
14 changes: 13 additions & 1 deletion src/libexpr/value.hh
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class BindingsBuilder;


typedef enum {
tUninitialized = 0,
tInt = 1,
tBool,
tString,
Expand Down Expand Up @@ -166,7 +167,7 @@ public:
struct Value
{
private:
InternalType internalType;
InternalType internalType = tUninitialized;

friend std::string showType(const Value & v);

Expand Down Expand Up @@ -270,6 +271,7 @@ public:
inline ValueType type(bool invalidIsThunk = false) const
{
switch (internalType) {
case tUninitialized: break;
case tInt: return nInt;
case tBool: return nBool;
case tString: return nString;
Expand All @@ -294,6 +296,16 @@ public:
internalType = newType;
}

/**
* A value becomes valid when it is initialized. We don't use this
* in the evaluator; only in the bindings, where the slight extra
* cost is warranted because of inexperienced callers.
*/
inline bool isValid() const
{
return internalType != tUninitialized;
}

inline void mkInt(NixInt n)
{
finishValue(tInt, { .integer = n });
Expand Down