xref: /aosp_15_r20/external/tink/cc/output_stream_with_result.h (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1 // Copyright 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ///////////////////////////////////////////////////////////////////////////////
16 
17 #ifndef TINK_OUTPUT_STREAM_WITH_RESULT_H_
18 #define TINK_OUTPUT_STREAM_WITH_RESULT_H_
19 
20 #include <type_traits>
21 
22 #include "tink/output_stream.h"
23 #include "tink/util/status.h"
24 #include "tink/util/statusor.h"
25 
26 namespace crypto {
27 namespace tink {
28 
29 // TODO(tholenst): Forward declare ExtractStatus function,
30 // as discussed in cl/269918867.
31 namespace internal {
32 // Closes the OutputStream and returns the status,
33 // for when ResultType is StatusOr<T>
34 template <class ResultType>
35 auto ExtractStatus(const ResultType& result)
36     -> decltype(std::declval<ResultType>().status()) {
37   return result.status();
38 }
39 
40 // Closes the OutputStream and returns the status,
41 // for when ResultType is Status
42 template <class ResultType>
43 auto ExtractStatus(ResultType result) ->
44     typename std::enable_if<std::is_same<ResultType, util::Status>::value,
45                             util::Status>::type {
46   return result;
47 }
48 }  // namespace internal
49 
50 // An abstract OutputStream subclass that acts as a sink for data and returns a
51 // result after the stream has been closed.
52 // The result is only available if the stream was able to close with an ok
53 // status. Otherwise, the status of the GetResult call will be the same status
54 // as the Close call had. If Close is successful, GetResult is guaranteed to
55 // return a valid result.
56 // The return type of GetResult will be StatusOr<T>, except for T == Status, in
57 // which case the return type is Status.
58 template <class T>
59 class OutputStreamWithResult : public OutputStream {
60  public:
OutputStreamWithResult()61   OutputStreamWithResult() : closed_(false) {}
62   ~OutputStreamWithResult() override = default;
63 
64   // The return type is StatusOr<T> if T != Status, and Status otherwise.
65   using ResultType =
66       typename std::conditional<std::is_same<T, util::Status>::value,
67                                 util::Status, util::StatusOr<T>>::type;
68 
69   // Get the result associated with this OutputStream. Can only be called on
70   // closed streams, and will otherwise fail with FAILED_PRECONDITION as error
71   // code.
72   // If Close() returned an ok status, this method is guaranteed to contain a
73   // valid result.
74   // The return type is StatusOr<T> if T != Status, and Status otherwise.
GetResult()75   ResultType GetResult() {
76     if (!closed_) {
77       return util::Status(absl::StatusCode::kFailedPrecondition,
78                           "Stream is not closed");
79     }
80     return result_;
81   }
82 
83   // Close the stream and return the computed result. Equivalent to calling
84   // Close() and GetResult() if Close() returned an OK status.
85   // The return type is StatusOr<T> if T != Status, and Status otherwise.
CloseAndGetResult()86   ResultType CloseAndGetResult() {
87     util::Status closing_status = Close();
88     if (!closing_status.ok()) {
89       return closing_status;
90     }
91     return GetResult();
92   }
93 
94   // Closes the OutputStream.
Close()95   util::Status Close() final {
96     if (closed_) {
97       return util::Status(absl::StatusCode::kFailedPrecondition,
98                           "Stream closed");
99     }
100     result_ = CloseStreamAndComputeResult();
101     closed_ = true;
102 
103     return internal::ExtractStatus(result_);
104   }
105 
106   // Getting the next OutputStream buffer. See OutputStream for detailed
107   // description.
Next(void ** data)108   crypto::tink::util::StatusOr<int> Next(void** data) final {
109     if (closed_) {
110       return util::Status(absl::StatusCode::kFailedPrecondition,
111                           "Write on closed Stream");
112     }
113     return NextBuffer(data);
114   }
115 
116  protected:
117   // Compute the result for this OutputStream. Safe for thread safety problems,
118   // this method will only be called once.
119   // The return type is StatusOr<T> if T != Status, and Status otherwise.
120   virtual ResultType CloseStreamAndComputeResult() = 0;
121   // Getting the next OutputStream buffer. See OutputStream for detailed
122   // description.
123   virtual util::StatusOr<int> NextBuffer(void** data) = 0;
124 
125  private:
126   bool closed_;
127   ResultType result_;
128 };
129 
130 }  // namespace tink
131 }  // namespace crypto
132 
133 #endif  // TINK_OUTPUT_STREAM_WITH_RESULT_H_
134