#ifndef THIRD_PARTY_UPB_WASM_ABI_STATUS_UTIL_H_
#define THIRD_PARTY_UPB_WASM_ABI_STATUS_UTIL_H_

#include "third_party/absl/base/attributes.h"
#include "third_party/absl/base/nullability.h"
#include "third_party/absl/base/optimization.h"
#include "third_party/absl/status/status.h"
#include "third_party/absl/strings/string_view.h"

// Must be last.
#include "wasm_abi/def.inc"

namespace upb::wasm {

// The constructor / destructor for StatusOr is very expensive and can drag
// performance for hot code paths like in UPB Wasm. To avoid this cost, Status
// is only constructed for error cases.
// To accommodate this, functions take a nullable Status pointer as nonnull out
// parameter (i.e. a Status double pointer). To simplify the pattern and ensure
// consistent nullability, we define the below alias for the core nullable
// Status pointer.
// UPB API functions should take a `MaybeErrorStatus* absl_nonnull` as parameter
// and call `SetStatus` below on detecting an error.
using MaybeErrorStatus = absl::Status* absl_nullable;

// Sets the `status` pointer to a new status with the given `statusCode` and
// `message`.
// If the `status` pointer is already set, it is replaced with a new
// status with the old status code and the new `message` is appended.
UPB_WASM_PRESERVE_ALL ABSL_ATTRIBUTE_NOINLINE void SetStatus(
    MaybeErrorStatus* absl_nonnull status, absl::StatusCode statusCode,
    absl::string_view message);

// TODO: b/383364109 - Do we need to check the status after every handle lookup?
// Potentially we can check the status once after all the handles are resolved.
#define WASM_UPB_ASSIGN_OR_RETURN(Type, result, expr, status) \
  Type result = (expr);                                       \
  if (ABSL_PREDICT_FALSE(*status != nullptr)) {               \
    return;                                                   \
  }

#define WASM_UPB_ASSIGN_OR_RETURN_VALUE(Type, result, expr, status, \
                                        default_value)              \
  Type result = (expr);                                             \
  if (ABSL_PREDICT_FALSE(*status != nullptr)) {                     \
    return default_value;                                           \
  }
}  // namespace upb::wasm

#include "wasm_abi/undef.inc"

#endif  // THIRD_PARTY_UPB_WASM_ABI_STATUS_UTIL_H_
