Asylo
status_helpers.h
Go to the documentation of this file.
1 /*
2  * Copyright 2021 Asylo authors
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 ASYLO_UTIL_STATUS_HELPERS_H_
18 #define ASYLO_UTIL_STATUS_HELPERS_H_
19 
20 #include <string>
21 
22 #include "absl/strings/string_view.h"
23 #include "absl/types/optional.h"
24 #include "asylo/util/status.h"
25 #include "asylo/util/status.pb.h"
26 #include "asylo/util/status_helpers_internal.h"
27 #include "asylo/util/statusor.h"
28 
29 namespace asylo {
30 
31 /// Converts a status-like object to another status type.
32 ///
33 /// The source and target types must:
34 ///
35 /// * Have a two-parameter constructor that takes an enum as its first
36 /// parameter and a string as its second parameter.
37 /// * Have non-static `const` `error_code()`, `error_message()`, and `ok()`
38 /// methods.
39 ///
40 /// This function is provided for the convenience of Asylo-SDK consumers
41 /// utilizing other status types such as `::grpc::Status`.
42 ///
43 /// Note that all statuses are converted to the canonical error space, so
44 /// additional error space information is lost.
45 ///
46 /// Payloads are preserved if both input and output status types support them.
47 ///
48 /// \param from_status A status-like object to copy.
49 /// \return A status-like object copied from `from_status`.
50 template <typename ToStatusT, typename FromStatusT>
51 ToStatusT ConvertStatus(const FromStatusT &from_status) {
52  return internal::ConvertStatusImpl<ToStatusT, FromStatusT>::Convert(
53  from_status);
54 }
55 
56 /// Exports the contents of `status` into a `StatusProto`. This function sets
57 /// the `space` and `canonical_code` fields in `status_proto` even if `status`
58 /// is in the canonical error space.
59 ///
60 /// \param status A `Status` to pack into a proto.
61 /// \return A `StatusProto` representing `status`.
63 
64 /// Returns a `Status` based on the contents of the given `status_proto`.
65 ///
66 /// If the error space given by `status_proto.space()` is unrecognized, the
67 /// returned `Status` is in the canonical error space and has an error code
68 /// equal to `status_proto.canonical_code()`. If `status_proto` has no canonical
69 /// code, the returned `Status` has an error code of
70 /// `absl::StatusCode::kUnknown`. Note that the error message is only set if
71 /// `status_proto` represents a non-OK status.
72 ///
73 /// If the given `status_proto` is invalid, then the returned `Status` has an
74 /// appropriate error code and message. A `StatusProto` is valid if and only if
75 /// all the following conditions hold:
76 ///
77 /// * If `code()` is 0, then `canonical_code()` is set to 0.
78 /// * If `canonical_code()` is 0, then `code()` is set to 0.
79 /// * If the error space is recognized, then `canonical_code()` is equal to
80 /// the equivalent canonical code given by the error space.
81 ///
82 /// \param status_proto A protobuf object to unpack.
83 /// \return A `Status` based on the contents of `status_proto`.
85 
86 /// Returns the type URL associated with a given protobuf message type. This
87 /// should be used when embedding a message of that type as a payload in a
88 /// `Status`.
89 ///
90 /// \return The type URL to use for `MessageT` payloads.
91 template <typename MessageT>
92 std::string GetTypeUrl() {
93  return internal::ProtoPayloadImpl<MessageT>::GetTypeUrl();
94 }
95 
96 /// Gets the payload of type `MessageT` in `status`. `MessageT` must be a
97 /// protobuf message type.
98 ///
99 /// The `status` argument may be either an Asylo `Status` or an `absl::Status`.
100 ///
101 /// \param status The status to find the payload in.
102 /// \return The payload of type `MessageT` in `status`, or `absl::nullopt` if
103 /// `status` contains no payload of the given type. Also returns
104 /// `absl::nullopt` if there was a parsing error.
105 template <typename MessageT, typename StatusT = Status>
107  return internal::ProtoPayloadImpl<MessageT, StatusT>::GetPayload(status);
108 }
109 
110 /// Adds a payload of type `MessageT` to `status`. `MessageT` must be a protobuf
111 /// message type. Note that a `Status` can only have one payload of any given
112 /// message type.
113 ///
114 /// The message is embedded with the same type URL that would be used to pack
115 /// the message into a `google::protobuf::Any`.
116 ///
117 /// The `status` argument may be either an Asylo `Status` or an `absl::Status`.
118 ///
119 /// \param message A protobuf message object.
120 /// \param[in,out] status The status to add the payload to.
121 template <typename MessageT, typename StatusT = Status>
122 void SetProtoPayload(const MessageT &message, StatusT &status) {
123  internal::ProtoPayloadImpl<MessageT, StatusT>::SetPayload(message, status);
124 }
125 
126 /// Returns the `Status` with the provided context prepended to its error
127 /// message. Returns `OkStatus()` if the given `Status` is OK.
128 ///
129 /// \param status A `Status` to add context to.
130 /// \param context Additional context to add to the `Status`.
131 /// \return `status` with `context` prepended, along with an appropriate
132 /// separator.
134 
135 /// As the `Status` overload above, but for `StatusOr<T>`.
136 ///
137 /// \param status A `StatusOr<T>` to add context to, if it is not OK.
138 /// \param context Additional context to add to the `Status`.
139 /// \return `status_or` if it is OK, otherwise `status_or.status()` with
140 /// `context` prepended to the error message.
141 template <typename T>
143  if (status_or.ok()) {
144  return status_or;
145  }
146  return WithContext(status_or.status(), context);
147 }
148 
149 /// As the `StatusOr<T>` overload above, but for `absl::StatusOr<T>`.
150 ///
151 /// \param status An `absl::StatusOr<T>` to add context to, if it is not OK.
152 /// \param context Additional context to add to the `absl::Status`.
153 /// \return `status_or` if it is OK, otherwise `status_or.status()` with
154 /// `context` prepended to the error message.
155 template <typename T>
158  if (status_or.ok()) {
159  return status_or;
160  }
161  return WithContext(status_or.status(), context);
162 }
163 
164 } // namespace asylo
165 
166 #endif // ASYLO_UTIL_STATUS_HELPERS_H_
void SetProtoPayload(const MessageT &message, StatusT &status)
Adds a payload of type MessageT to status.
Definition: status_helpers.h:122
ToStatusT ConvertStatus(const FromStatusT &from_status)
Converts a status-like object to another status type.
Definition: status_helpers.h:51
ABSL_CONST_INIT const char kStatusMoveAssignmentMsg[]
std::string GetTypeUrl()
Returns the type URL associated with a given protobuf message type.
Definition: status_helpers.h:92
absl::optional< MessageT > GetProtoPayload(const StatusT &status)
Gets the payload of type MessageT in status.
Definition: status_helpers.h:106
Status WithContext(const Status &status, absl::string_view context)
Returns the Status with the provided context prepended to its error message.
absl::StatusOr< T > WithContext(absl::StatusOr< T > status_or, absl::string_view context)
As the StatusOr<T> overload above, but for absl::StatusOr<T>.
Definition: status_helpers.h:156
StatusProto StatusToProto(const Status &status)
Exports the contents of status into a StatusProto.
Status StatusFromProto(const StatusProto &status_proto)
Returns a Status based on the contents of the given status_proto.