diff --git a/src/Val.cc b/src/Val.cc index 18c2f7335c..451c9f6428 100644 --- a/src/Val.cc +++ b/src/Val.cc @@ -891,8 +891,8 @@ unsigned int StringVal::ComputeFootprint(std::unordered_set* analyze return 1 /* this object */ + static_cast(Len()) / sizeof(Val); } -static std::variant BuildVal(const rapidjson::Value& j, const TypePtr& t, - const FuncPtr& key_func) { +static zeek::expected BuildVal(const rapidjson::Value& j, const TypePtr& t, + const FuncPtr& key_func) { auto mismatch_err = [t, &j]() { std::string json_type; switch ( j.GetType() ) { @@ -906,7 +906,8 @@ static std::variant BuildVal(const rapidjson::Value& j, con default: json_type = "unknown"; } - return util::fmt("cannot convert JSON type '%s' to Zeek type '%s'", json_type.c_str(), type_name(t->Tag())); + return zeek::unexpected( + util::fmt("cannot convert JSON type '%s' to Zeek type '%s'", json_type.c_str(), type_name(t->Tag()))); }; if ( j.IsNull() ) @@ -960,7 +961,7 @@ static std::variant BuildVal(const rapidjson::Value& j, con parts.erase(std::remove_if(parts.begin(), parts.end(), [](auto x) { return x.empty(); }), parts.end()); if ( (parts.size() % 2) != 0 ) - return "wrong interval format, must be pairs of values with units"; + return zeek::unexpected("wrong interval format, must be pairs of values with units"); double interval_secs = 0.0; for ( size_t i = 0; i < parts.size(); i += 2 ) { @@ -980,7 +981,8 @@ static std::variant BuildVal(const rapidjson::Value& j, con else if ( unit == "usec" || unit == "usecs" ) interval_secs += (value * Microseconds); else - return util::fmt("wrong interval format, invalid unit type %s", unit.data()); + return zeek::unexpected( + util::fmt("wrong interval format, invalid unit type %s", unit.data())); } return make_intrusive(interval_secs, Seconds); @@ -991,11 +993,10 @@ static std::variant BuildVal(const rapidjson::Value& j, con case TYPE_PORT: { if ( j.IsString() ) { - int port = 0; if ( j.GetStringLength() > 0 && j.GetStringLength() < 10 ) { char* slash; errno = 0; - port = strtol(j.GetString(), &slash, 10); + auto port = strtol(j.GetString(), &slash, 10); if ( ! errno ) { ++slash; if ( util::streq(slash, "tcp") ) @@ -1009,15 +1010,17 @@ static std::variant BuildVal(const rapidjson::Value& j, con } } - return "wrong port format, string must be /[0-9]{1,5}\\/(tcp|udp|icmp|unknown)/"; + return zeek::unexpected( + "wrong port format, string must be /[0-9]{1,5}\\/(tcp|udp|icmp|unknown)/"); } else if ( j.IsObject() ) { if ( ! j.HasMember("port") || ! j.HasMember("proto") ) - return "wrong port format, object must have 'port' and 'proto' members"; + return zeek::unexpected( + "wrong port format, object must have 'port' and 'proto' members"); if ( ! j["port"].IsNumber() ) - return "wrong port format, port must be a number"; + return zeek::unexpected("wrong port format, port must be a number"); if ( ! j["proto"].IsString() ) - return "wrong port format, protocol must be a string"; + return zeek::unexpected("wrong port format, protocol must be a string"); std::string proto{j["proto"].GetString()}; @@ -1030,10 +1033,10 @@ static std::variant BuildVal(const rapidjson::Value& j, con if ( proto == "unknown" ) return val_mgr->Port(j["port"].GetInt(), TRANSPORT_UNKNOWN); - return "wrong port format, invalid protocol string"; + return zeek::unexpected("wrong port format, invalid protocol string"); } else - return "wrong port format, must be string or object"; + return zeek::unexpected("wrong port format, must be string or object"); } case TYPE_PATTERN: { @@ -1055,7 +1058,7 @@ static std::variant BuildVal(const rapidjson::Value& j, con auto re = std::make_unique(candidate.c_str()); if ( ! re->Compile() ) - return "error compiling pattern"; + return zeek::unexpected("error compiling pattern"); return make_intrusive(re.release()); } @@ -1074,7 +1077,7 @@ static std::variant BuildVal(const rapidjson::Value& j, con std::string_view subnet_sv(j.GetString(), j.GetStringLength()); auto pos = subnet_sv.find('/'); if ( pos == subnet_sv.npos ) - return util::fmt("invalid value for subnet: '%s'", j.GetString()); + return zeek::unexpected(util::fmt("invalid value for subnet: '%s'", j.GetString())); candidate = std::string(j.GetString(), pos); @@ -1082,7 +1085,7 @@ static std::variant BuildVal(const rapidjson::Value& j, con char* end; width = strtol(subnet_sv.data() + pos + 1, &end, 10); if ( subnet_sv.data() + pos + 1 == end || errno ) - return util::fmt("invalid value for subnet: '%s'", j.GetString()); + return zeek::unexpected(util::fmt("invalid value for subnet: '%s'", j.GetString())); } if ( candidate.front() == '[' ) @@ -1104,7 +1107,8 @@ static std::variant BuildVal(const rapidjson::Value& j, con auto intval = et->Lookup({j.GetString(), j.GetStringLength()}); if ( intval < 0 ) - return util::fmt("'%s' is not a valid enum for '%s'.", j.GetString(), et->GetName().c_str()); + return zeek::unexpected( + util::fmt("'%s' is not a valid enum for '%s'.", j.GetString(), et->GetName().c_str())); return et->GetEnumVal(intval); } @@ -1126,19 +1130,19 @@ static std::variant BuildVal(const rapidjson::Value& j, con return mismatch_err(); for ( const auto& item : j.GetArray() ) { - std::variant v; + zeek::expected v; if ( tl->GetTypes().size() == 1 ) v = BuildVal(item, tl->GetPureType(), key_func); else v = BuildVal(item, tl, key_func); - if ( ! get_if(&v) ) + if ( ! v ) return v; - if ( ! std::get(v) ) + if ( v.value() == nullptr ) continue; - tv->Assign(std::move(std::get(v)), nullptr); + tv->Assign(v.value(), nullptr); } return tv; @@ -1151,7 +1155,7 @@ static std::variant BuildVal(const rapidjson::Value& j, con rapidjson::Document idxstr; idxstr.Parse(it->name.GetString(), it->name.GetStringLength()); - std::variant idx; + zeek::expected idx; if ( tl->GetTypes().size() > 1 ) idx = BuildVal(idxstr, tl, key_func); @@ -1163,19 +1167,19 @@ static std::variant BuildVal(const rapidjson::Value& j, con // Parse the string's content, not the full JSON string. idx = BuildVal(idxstr, tl->GetPureType(), key_func); - if ( ! get_if(&idx) ) + if ( ! idx ) return idx; - if ( ! std::get(idx) ) + if ( idx.value() == nullptr ) continue; auto v = BuildVal(it->value, tt->Yield(), key_func); - if ( ! get_if(&v) ) + if ( ! v ) return v; - if ( ! std::get(v) ) + if ( v.value() == nullptr ) continue; - tv->Assign(std::move(std::get(idx)), std::move(std::get(v))); + tv->Assign(idx.value(), v.value()); } return tv; @@ -1202,7 +1206,7 @@ static std::variant BuildVal(const rapidjson::Value& j, con } if ( ! result ) - return "key function error"; + return zeek::unexpected("key function error"); normalized_keys[result->AsStringVal()->CheckString()] = &it->value; } @@ -1226,17 +1230,18 @@ static std::variant BuildVal(const rapidjson::Value& j, con if ( ! td_i->GetAttr(detail::ATTR_OPTIONAL) && ! td_i->GetAttr(detail::ATTR_DEFAULT) ) // jval being set means it is a null JSON value else // it wasn't even there. - return util::fmt("required field %s$%s is %s in JSON", t->GetName().c_str(), td_i->id, - jval ? "null" : "missing"); + return zeek::unexpected(util::fmt("required field %s$%s is %s in JSON", + t->GetName().c_str(), td_i->id, + jval ? "null" : "missing")); continue; } auto v = BuildVal(*jval, td_i->type, key_func); - if ( ! get_if(&v) ) + if ( ! v ) return v; - rv->Assign(i, std::move(std::get(v))); + rv->Assign(i, v.value()); } return rv; @@ -1249,16 +1254,16 @@ static std::variant BuildVal(const rapidjson::Value& j, con auto lt = t->AsTypeList(); if ( j.GetArray().Size() < lt->GetTypes().size() ) - return "index type doesn't match"; + return zeek::unexpected("index type doesn't match"); auto lv = make_intrusive(TYPE_ANY); for ( size_t i = 0; i < lt->GetTypes().size(); i++ ) { auto v = BuildVal(j.GetArray()[i], lt->GetTypes()[i], key_func); - if ( ! get_if(&v) ) + if ( ! v ) return v; - lv->Append(std::move(std::get(v))); + lv->Append(v.value()); } return lv; @@ -1272,29 +1277,30 @@ static std::variant BuildVal(const rapidjson::Value& j, con auto vv = make_intrusive(IntrusivePtr{NewRef{}, vt}); for ( const auto& item : j.GetArray() ) { auto v = BuildVal(item, vt->Yield(), key_func); - if ( ! get_if(&v) ) + if ( ! v ) return v; - if ( ! std::get(v) ) + if ( v.value() == nullptr ) continue; - vv->Assign(vv->Size(), std::move(std::get(v))); + vv->Assign(vv->Size(), v.value()); } return vv; } - default: return util::fmt("type '%s' unsupported", type_name(t->Tag())); + default: return zeek::unexpected(util::fmt("type '%s' unsupported", type_name(t->Tag()))); } } -std::variant detail::ValFromJSON(std::string_view json_str, const TypePtr& t, - const FuncPtr& key_func) { +zeek::expected detail::ValFromJSON(std::string_view json_str, const TypePtr& t, + const FuncPtr& key_func) { rapidjson::Document doc; rapidjson::ParseResult ok = doc.Parse(json_str.data(), json_str.length()); if ( ! ok ) - return util::fmt("JSON parse error: %s Offset: %lu", rapidjson::GetParseError_En(ok.Code()), ok.Offset()); + return zeek::unexpected( + util::fmt("JSON parse error: %s Offset: %lu", rapidjson::GetParseError_En(ok.Code()), ok.Offset())); return BuildVal(doc, t, key_func); } diff --git a/src/Val.h b/src/Val.h index bc6de01ddd..850b89dc81 100644 --- a/src/Val.h +++ b/src/Val.h @@ -1774,8 +1774,8 @@ namespace detail { // // The *key_func* parameter is a Zeek script function called for every JSON key // for normalization. If Func::nil is passed, no normalization happens. -extern std::variant ValFromJSON(std::string_view json_str, const TypePtr& t, - const FuncPtr& key_func); +extern zeek::expected ValFromJSON(std::string_view json_str, const TypePtr& t, + const FuncPtr& key_func); // If the given vector is an empty vector-of-any ("unspecified"), // concretizes it to the given type. *v* gives the vector and *t* the diff --git a/src/storage/backend/redis/Redis.cc b/src/storage/backend/redis/Redis.cc index 47666a3c4d..3e5a4f30d5 100644 --- a/src/storage/backend/redis/Redis.cc +++ b/src/storage/backend/redis/Redis.cc @@ -440,10 +440,10 @@ void Redis::HandleGetResult(redisReply* reply, ResultCallback* callback) { res = ParseReplyError("get", reply->str); else { auto val = zeek::detail::ValFromJSON(reply->str, val_type, Func::nil); - if ( std::holds_alternative(val) ) - res = {ReturnCode::SUCCESS, "", std::get(val)}; + if ( val ) + res = {ReturnCode::SUCCESS, "", val.value()}; else - res = {ReturnCode::OPERATION_FAILED, std::get(val)}; + res = {ReturnCode::OPERATION_FAILED, val.error()}; } freeReplyObject(reply); diff --git a/src/storage/backend/sqlite/SQLite.cc b/src/storage/backend/sqlite/SQLite.cc index 4758ac071c..a51c2f21bf 100644 --- a/src/storage/backend/sqlite/SQLite.cc +++ b/src/storage/backend/sqlite/SQLite.cc @@ -270,13 +270,11 @@ OperationResult SQLite::Step(sqlite3_stmt* stmt, bool parse_value) { const char* text = (const char*)sqlite3_column_text(stmt, 0); auto val = zeek::detail::ValFromJSON(text, val_type, Func::nil); sqlite3_reset(stmt); - if ( std::holds_alternative(val) ) { - ValPtr val_v = std::get(val); - ret = {ReturnCode::SUCCESS, "", val_v}; - } - else { - ret = {ReturnCode::OPERATION_FAILED, std::get(val)}; - } + + if ( val ) + ret = {ReturnCode::SUCCESS, "", val.value()}; + else + ret = {ReturnCode::OPERATION_FAILED, val.error()}; } else { ret = {ReturnCode::OPERATION_FAILED, "sqlite3_step should not have returned a value"}; diff --git a/src/supervisor/Supervisor.cc b/src/supervisor/Supervisor.cc index 0585ec6467..22e43f004d 100644 --- a/src/supervisor/Supervisor.cc +++ b/src/supervisor/Supervisor.cc @@ -1363,8 +1363,8 @@ RecordValPtr Supervisor::NodeConfig::ToRecord() const { auto tt = rt->GetFieldType("cluster"); auto json_res = detail::ValFromJSON(cluster, tt, Func::nil); - if ( auto val = std::get_if(&json_res) ) { - rval->AssignField("cluster", *val); + if ( json_res ) { + rval->AssignField("cluster", json_res.value()); } else { // This should never happen: the JSON data comes from a table[string] of @@ -1372,7 +1372,7 @@ RecordValPtr Supervisor::NodeConfig::ToRecord() const { // here can be hard to debug. Other JSON code (see FromJSON()) fails // silently when the JSON is misformatted. We just warn: fprintf(stderr, "Could not parse %s's cluster table from '%s': %s\n", name.c_str(), cluster.c_str(), - std::get(json_res).c_str()); + json_res.error().c_str()); rval->AssignField("cluster", make_intrusive(std::move(tt))); } diff --git a/src/zeek.bif b/src/zeek.bif index 7c5fac0f09..8702a0a7fa 100644 --- a/src/zeek.bif +++ b/src/zeek.bif @@ -5268,15 +5268,15 @@ function from_json%(s: string, t: any, key_func: string_mapper &default=from_jso auto res = zeek::detail::ValFromJSON(s->ToStdStringView(), t->AsType()->AsTypeType()->GetType(), key_func_ptr); - if ( auto val = std::get_if(&res) ) + if ( res ) { - rval->Assign(v_idx, *val); + rval->Assign(v_idx, res.value()); rval->Assign(valid_idx, true); } else { rval->Assign(valid_idx, false); - zeek::emit_builtin_error(std::get(res).c_str()); + zeek::emit_builtin_error(res.error().c_str()); } return std::move(rval);