blob: ae57d72ced3a1af4f8e78075404cce6969c2aad9 [file] [log] [blame]
// Copyright 2024 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef LIB_DL_STATEFUL_ERROR_H_
#define LIB_DL_STATEFUL_ERROR_H_
#include <lib/fit/result.h>
#include "error.h"
namespace dl {
// dl::StatefulError holds a dl::Error object for use in the dlerror() model.
// It's used as `return gPerThreadErrorState(..., error_value);` where ...
// returns some `fit::result<dl::Error, T>` type and error_value is a T. That
// sets the error state that GetAndClearLastError() returns like dlerror().
class StatefulError {
public:
// Convert the fit::result<dl::Error, T> return value into just a T.
// If result.is_error() then
template <typename T, typename U>
T operator()(fit::result<Error, T> result, U error_value) {
if (result.is_error()) {
error_.ClearAndAssign(std::move(result).error_value());
return error_value;
}
return std::move(result).value();
}
// This works like dlerror(): it returns nullptr if there hasn't been a
// failing call since the last GetAndClearLastError call. Regardless,
// it ends the lifetime of the last string returned by a previous call.
[[nodiscard]] const char* GetAndClearLastError() { return error_.take_c_str_or_clear(); }
// Destruction is always harmless, unlike dl::Error.
~StatefulError() { error_.clear(); }
private:
Error error_;
};
// This is the main instance that's used by the <dlfcn.h> C API functions
// to provide the dlerror() API model.
extern thread_local StatefulError gPerThreadErrorState;
} // namespace dl
#endif // LIB_DL_STATEFUL_ERROR_H_