mirror of
https://github.com/abseil/abseil-cpp.git
synced 2026-06-04 12:07:05 +08:00
197 lines
6.5 KiB
C++
197 lines
6.5 KiB
C++
// Copyright 2026 The Abseil Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include "absl/status/status_builder.h"
|
|
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <ostream>
|
|
#include <string>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
|
|
#include "absl/base/attributes.h"
|
|
#include "absl/base/config.h"
|
|
#include "absl/base/macros.h"
|
|
#include "absl/status/status.h"
|
|
#include "absl/strings/cord.h"
|
|
#include "absl/strings/str_cat.h"
|
|
#include "absl/strings/string_view.h"
|
|
#include "absl/time/time.h"
|
|
#include "absl/types/source_location.h"
|
|
|
|
namespace absl {
|
|
ABSL_NAMESPACE_BEGIN
|
|
|
|
void StatusBuilder::Destroy(std::unique_ptr<Rep>) {
|
|
// nothing to do. The unique_ptr will do the cleanup.
|
|
}
|
|
|
|
// These constructors are not-inlined and defined in the .cc file to reduce
|
|
// binary size. See cl/354351433 for a quantification.
|
|
StatusBuilder::StatusBuilder() {}
|
|
|
|
StatusBuilder::StatusBuilder(const absl::Status& original_status,
|
|
absl::SourceLocation location)
|
|
: loc_(location), rep_(InitRep(original_status)) {}
|
|
|
|
StatusBuilder::operator absl::Status() const& {
|
|
if (rep_ == nullptr) return absl::Status();
|
|
return CreateStatusAndConditionallyLog(loc_, std::make_unique<Rep>(*rep_));
|
|
}
|
|
|
|
StatusBuilder::Rep::Rep(const absl::Status& s) : status(s) {}
|
|
StatusBuilder::Rep::Rep(absl::Status&& s) : status(std::move(s)) {}
|
|
StatusBuilder::Rep::~Rep() {}
|
|
|
|
StatusBuilder::Rep* StatusBuilder::InitRepImpl(absl::Status s) {
|
|
if (s.ok()) {
|
|
return nullptr;
|
|
} else {
|
|
return new Rep(std::move(s));
|
|
}
|
|
}
|
|
|
|
StatusBuilder::Rep::Rep(const Rep& r)
|
|
: status(r.status),
|
|
logging_mode(r.logging_mode),
|
|
log_severity(r.log_severity),
|
|
verbose_level(r.verbose_level),
|
|
n(r.n),
|
|
period(r.period),
|
|
stream_message(r.stream_message),
|
|
sink(r.sink),
|
|
message_join_style(r.message_join_style),
|
|
should_log_stack_trace(r.should_log_stack_trace),
|
|
also_send_to_log(r.also_send_to_log) {
|
|
if (r.stream.has_value()) {
|
|
InitStream();
|
|
}
|
|
}
|
|
|
|
void StatusBuilder::Rep::InitStream() { stream.emplace(stream_message); }
|
|
|
|
bool StatusBuilder::HasPayload() const {
|
|
static constexpr absl::string_view kMessageSetUrl =
|
|
"type.googleapis.com/util.MessageSetPayload";
|
|
return rep_ != nullptr && rep_->status.GetPayload(kMessageSetUrl).has_value();
|
|
}
|
|
|
|
ABSL_ATTRIBUTE_WEAK StatusBuilder& StatusBuilder::SetCode(
|
|
absl::StatusCode code) & {
|
|
if (rep_ == nullptr) {
|
|
rep_ = std::make_unique<StatusBuilder::Rep>(
|
|
absl::Status(code, absl::string_view(), absl::SourceLocation()));
|
|
} else {
|
|
absl::Status status(code, absl::string_view(), absl::SourceLocation());
|
|
rep_->status.ForEachPayload(
|
|
[&status](absl::string_view type_url, const absl::Cord& payload) {
|
|
status.SetPayload(type_url, payload);
|
|
});
|
|
rep_->status = std::move(status);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
ABSL_ATTRIBUTE_WEAK void AbslInternalSetErrorCode(StatusBuilder& builder,
|
|
absl::StatusCode code) {
|
|
builder.SetCode(code);
|
|
}
|
|
|
|
class status_internal::StatusPrivateAccessorForStatusBuilder {
|
|
public:
|
|
static absl::Status SetMessage(const absl::Status& status,
|
|
absl::string_view message) {
|
|
ABSL_ASSERT(!status.ok());
|
|
|
|
if (message.empty()) {
|
|
return absl::Status(status.code(), message, absl::SourceLocation());
|
|
}
|
|
|
|
using StatusRep =
|
|
std::remove_cv_t<std::remove_pointer_t<decltype(Status::RepToPointer(
|
|
std::declval<uintptr_t>()))>>;
|
|
StatusRep* rep;
|
|
if (Status::IsInlined(status.rep_)) {
|
|
rep = new StatusRep(Status::InlinedRepToCode(status.rep_), message,
|
|
nullptr);
|
|
} else {
|
|
rep = Status::RepToPointer(status.rep_)->Clone(message, true, true);
|
|
}
|
|
return absl::Status(Status::PointerToRep(rep));
|
|
}
|
|
|
|
static absl::Status JoinMessageToStatus(absl::Status s, absl::string_view msg,
|
|
MessageJoinStyle style) {
|
|
if (s.ok() || msg.empty()) return s;
|
|
const absl::string_view original_message = s.message();
|
|
switch (style) {
|
|
case MessageJoinStyle::kAnnotate: {
|
|
std::string annotated;
|
|
if (!original_message.empty()) {
|
|
absl::StrAppend(&annotated, original_message, "; ", msg);
|
|
msg = annotated;
|
|
}
|
|
return SetMessage(s, msg);
|
|
}
|
|
case MessageJoinStyle::kPrepend:
|
|
return SetMessage(s, absl::StrCat(msg, original_message));
|
|
case MessageJoinStyle::kAppend:
|
|
return SetMessage(s, absl::StrCat(original_message, msg));
|
|
default:
|
|
return absl::InternalError("Unknown MessageJoinStyle");
|
|
}
|
|
}
|
|
};
|
|
|
|
ABSL_ATTRIBUTE_WEAK std::string StatusBuilder::CurrentStackTrace() {
|
|
return std::string();
|
|
}
|
|
|
|
ABSL_ATTRIBUTE_WEAK absl::Status StatusBuilder::CreateStatusAndConditionallyLog(
|
|
absl::SourceLocation loc, std::unique_ptr<Rep> rep) {
|
|
if (rep == nullptr) return absl::OkStatus();
|
|
absl::Status result = status_internal::StatusPrivateAccessorForStatusBuilder::
|
|
JoinMessageToStatus(std::move(rep->status), rep->stream_message,
|
|
rep->message_join_style);
|
|
// Passing in the `loc` last to ensure the sequence of the source locations.
|
|
result.AddSourceLocation(loc);
|
|
return result;
|
|
}
|
|
|
|
ABSL_ATTRIBUTE_WEAK std::string StatusBuilder::ToString() const {
|
|
if (rep_ == nullptr) {
|
|
return absl::OkStatus().ToString();
|
|
}
|
|
|
|
return status_internal::StatusPrivateAccessorForStatusBuilder::
|
|
JoinMessageToStatus(rep_->status, rep_->stream_message,
|
|
rep_->message_join_style)
|
|
.WithSourceLocation(loc_)
|
|
.ToString();
|
|
}
|
|
|
|
ABSL_ATTRIBUTE_WEAK std::ostream& operator<<(std::ostream& os,
|
|
const StatusBuilder& builder) {
|
|
return os << static_cast<absl::Status>(builder);
|
|
}
|
|
|
|
ABSL_ATTRIBUTE_WEAK std::ostream& operator<<(std::ostream& os,
|
|
StatusBuilder&& builder) {
|
|
return os << static_cast<absl::Status>(std::move(builder));
|
|
}
|
|
|
|
ABSL_NAMESPACE_END
|
|
} // namespace absl
|