Action Engine
Loading...
Searching...
No Matches
status_builder.h
1/*
2 * Copyright 2025 Google LLC
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ACTIONENGINE_UTIL_STATUS_BUILDER_H_
18#define ACTIONENGINE_UTIL_STATUS_BUILDER_H_
19
20#include <memory>
21#include <sstream>
22#include <string_view>
23#include <utility>
24
25#include <absl/base/attributes.h>
26#include <absl/status/status.h>
27
28#include "actionengine/util/source_location.h"
29
30namespace act::util {
31
32class ABSL_MUST_USE_RESULT StatusBuilder {
33 public:
34 StatusBuilder(const StatusBuilder& sb);
35 StatusBuilder& operator=(const StatusBuilder& sb);
36
37 StatusBuilder(StatusBuilder&&) = default;
38 StatusBuilder& operator=(StatusBuilder&&) = default;
39
40 // Creates a `StatusBuilder` based on an original status. If logging is
41 // enabled, it will use `location` as the location from which the log message
42 // occurs. A typical user will call this with `ACTIONENGINE_LOC`.
43 StatusBuilder(const absl::Status& original_status,
44 act::util::source_location location)
45 : impl_(original_status.ok()
46 ? nullptr
47 : std::make_unique<Impl>(original_status, location)) {}
48
49 StatusBuilder(absl::Status&& original_status,
50 act::util::source_location location)
51 : impl_(original_status.ok()
52 ? nullptr
53 : std::make_unique<Impl>(std::move(original_status),
54 location)) {}
55
56 // Creates a `StatusBuilder` from a status code. If logging is
57 // enabled, it will use `location` as the location from which the log message
58 // occurs. A typical user will call this with `ACTIONENGINE_LOC`.
59 StatusBuilder(absl::StatusCode code, act::util::source_location location)
60 : impl_(code == absl::StatusCode::kOk
61 ? nullptr
62 : std::make_unique<Impl>(absl::Status(code, ""), location)) {}
63
64 bool ok() const { return !impl_; }
65
66 StatusBuilder& SetAppend() &;
67 StatusBuilder&& SetAppend() &&;
68
69 StatusBuilder& SetPrepend() &;
70 StatusBuilder&& SetPrepend() &&;
71
72 StatusBuilder& SetNoLogging() &;
73 StatusBuilder&& SetNoLogging() &&;
74
75 template <typename T>
76 StatusBuilder& operator<<(const T& msg) & {
77 if (!impl_)
78 return *this;
79 impl_->stream << msg;
80 return *this;
81 }
82
83 template <typename T>
84 StatusBuilder&& operator<<(const T& msg) && {
85 return std::move(*this << msg);
86 }
87
88 operator absl::Status() const&;
89 operator absl::Status() &&;
90
91 absl::Status JoinMessageToStatus();
92
93 private:
94 struct Impl {
95 // Specifies how to join the error message in the original status and any
96 // additional message that has been streamed into the builder.
97 enum class MessageJoinStyle {
98 kAnnotate,
99 kAppend,
100 kPrepend,
101 };
102
103 Impl(const absl::Status& status, act::util::source_location location);
104 Impl(absl::Status&& status, act::util::source_location location);
105 Impl(const Impl&);
106 Impl& operator=(const Impl&);
107
108 absl::Status JoinMessageToStatus();
109
110 // The status that the result will be based on.
111 absl::Status status;
112 // The source location to record if this file is logged.
113 act::util::source_location location;
114 // Logging disabled if true.
115 bool no_logging = false;
116 // The additional messages added with `<<`. This is nullptr when status_ is
117 // ok.
118 std::ostringstream stream;
119 // Specifies how to join the message in `status_` and `stream_`.
120 MessageJoinStyle join_style = MessageJoinStyle::kAnnotate;
121 };
122
123 // Internal store of data for the class. An invariant of the class is that
124 // this is null when the original status is okay, and not-null otherwise.
125 std::unique_ptr<Impl> impl_;
126};
127
128inline StatusBuilder AlreadyExistsErrorBuilder(
129 act::util::source_location location) {
130 return StatusBuilder(absl::StatusCode::kAlreadyExists, location);
131}
132
133inline StatusBuilder FailedPreconditionErrorBuilder(
134 act::util::source_location location) {
135 return StatusBuilder(absl::StatusCode::kFailedPrecondition, location);
136}
137
138inline StatusBuilder InternalErrorBuilder(act::util::source_location location) {
139 return StatusBuilder(absl::StatusCode::kInternal, location);
140}
141
142inline StatusBuilder InvalidArgumentErrorBuilder(
143 act::util::source_location location) {
144 return StatusBuilder(absl::StatusCode::kInvalidArgument, location);
145}
146
147inline StatusBuilder NotFoundErrorBuilder(act::util::source_location location) {
148 return StatusBuilder(absl::StatusCode::kNotFound, location);
149}
150
151inline StatusBuilder UnavailableErrorBuilder(
152 act::util::source_location location) {
153 return StatusBuilder(absl::StatusCode::kUnavailable, location);
154}
155
156inline StatusBuilder UnimplementedErrorBuilder(
157 act::util::source_location location) {
158 return StatusBuilder(absl::StatusCode::kUnimplemented, location);
159}
160
161inline StatusBuilder UnknownErrorBuilder(act::util::source_location location) {
162 return StatusBuilder(absl::StatusCode::kUnknown, location);
163}
164
165} // namespace act::util
166
167#endif // ACTIONENGINE_REDIS_STATUS_BUILDER_H_