Home | History | Annotate | Download | only in stubs
      1 // Protocol Buffers - Google's data interchange format
      2 // Copyright 2008 Google Inc.  All rights reserved.
      3 // https://developers.google.com/protocol-buffers/
      4 //
      5 // Redistribution and use in source and binary forms, with or without
      6 // modification, are permitted provided that the following conditions are
      7 // met:
      8 //
      9 //     * Redistributions of source code must retain the above copyright
     10 // notice, this list of conditions and the following disclaimer.
     11 //     * Redistributions in binary form must reproduce the above
     12 // copyright notice, this list of conditions and the following disclaimer
     13 // in the documentation and/or other materials provided with the
     14 // distribution.
     15 //     * Neither the name of Google Inc. nor the names of its
     16 // contributors may be used to endorse or promote products derived from
     17 // this software without specific prior written permission.
     18 //
     19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30 
     31 // StatusOr<T> is the union of a Status object and a T
     32 // object. StatusOr models the concept of an object that is either a
     33 // usable value, or an error Status explaining why such a value is
     34 // not present. To this end, StatusOr<T> does not allow its Status
     35 // value to be Status::OK. Further, StatusOr<T*> does not allow the
     36 // contained pointer to be NULL.
     37 //
     38 // The primary use-case for StatusOr<T> is as the return value of a
     39 // function which may fail.
     40 //
     41 // Example client usage for a StatusOr<T>, where T is not a pointer:
     42 //
     43 //  StatusOr<float> result = DoBigCalculationThatCouldFail();
     44 //  if (result.ok()) {
     45 //    float answer = result.ValueOrDie();
     46 //    printf("Big calculation yielded: %f", answer);
     47 //  } else {
     48 //    LOG(ERROR) << result.status();
     49 //  }
     50 //
     51 // Example client usage for a StatusOr<T*>:
     52 //
     53 //  StatusOr<Foo*> result = FooFactory::MakeNewFoo(arg);
     54 //  if (result.ok()) {
     55 //    std::unique_ptr<Foo> foo(result.ValueOrDie());
     56 //    foo->DoSomethingCool();
     57 //  } else {
     58 //    LOG(ERROR) << result.status();
     59 //  }
     60 //
     61 // Example client usage for a StatusOr<std::unique_ptr<T>>:
     62 //
     63 //  StatusOr<std::unique_ptr<Foo>> result = FooFactory::MakeNewFoo(arg);
     64 //  if (result.ok()) {
     65 //    std::unique_ptr<Foo> foo = result.ConsumeValueOrDie();
     66 //    foo->DoSomethingCool();
     67 //  } else {
     68 //    LOG(ERROR) << result.status();
     69 //  }
     70 //
     71 // Example factory implementation returning StatusOr<T*>:
     72 //
     73 //  StatusOr<Foo*> FooFactory::MakeNewFoo(int arg) {
     74 //    if (arg <= 0) {
     75 //      return ::util::Status(::util::error::INVALID_ARGUMENT,
     76 //                            "Arg must be positive");
     77 //    } else {
     78 //      return new Foo(arg);
     79 //    }
     80 //  }
     81 //
     82 
     83 #ifndef GOOGLE_PROTOBUF_STUBS_STATUSOR_H_
     84 #define GOOGLE_PROTOBUF_STUBS_STATUSOR_H_
     85 
     86 #include <new>
     87 #include <string>
     88 #include <utility>
     89 
     90 #include <google/protobuf/stubs/status.h>
     91 
     92 namespace google {
     93 namespace protobuf {
     94 namespace util {
     95 
     96 template<typename T>
     97 class StatusOr {
     98   template<typename U> friend class StatusOr;
     99 
    100  public:
    101   // Construct a new StatusOr with Status::UNKNOWN status
    102   StatusOr();
    103 
    104   // Construct a new StatusOr with the given non-ok status. After calling
    105   // this constructor, calls to ValueOrDie() will CHECK-fail.
    106   //
    107   // NOTE: Not explicit - we want to use StatusOr<T> as a return
    108   // value, so it is convenient and sensible to be able to do 'return
    109   // Status()' when the return type is StatusOr<T>.
    110   //
    111   // REQUIRES: status != Status::OK. This requirement is DCHECKed.
    112   // In optimized builds, passing Status::OK here will have the effect
    113   // of passing PosixErrorSpace::EINVAL as a fallback.
    114   StatusOr(const Status& status);  // NOLINT
    115 
    116   // Construct a new StatusOr with the given value. If T is a plain pointer,
    117   // value must not be NULL. After calling this constructor, calls to
    118   // ValueOrDie() will succeed, and calls to status() will return OK.
    119   //
    120   // NOTE: Not explicit - we want to use StatusOr<T> as a return type
    121   // so it is convenient and sensible to be able to do 'return T()'
    122   // when when the return type is StatusOr<T>.
    123   //
    124   // REQUIRES: if T is a plain pointer, value != NULL. This requirement is
    125   // DCHECKed. In optimized builds, passing a NULL pointer here will have
    126   // the effect of passing PosixErrorSpace::EINVAL as a fallback.
    127   StatusOr(const T& value);  // NOLINT
    128 
    129   // Copy constructor.
    130   StatusOr(const StatusOr& other);
    131 
    132   // Conversion copy constructor, T must be copy constructible from U
    133   template<typename U>
    134   StatusOr(const StatusOr<U>& other);
    135 
    136   // Assignment operator.
    137   StatusOr& operator=(const StatusOr& other);
    138 
    139   // Conversion assignment operator, T must be assignable from U
    140   template<typename U>
    141   StatusOr& operator=(const StatusOr<U>& other);
    142 
    143   // Returns a reference to our status. If this contains a T, then
    144   // returns Status::OK.
    145   const Status& status() const;
    146 
    147   // Returns this->status().ok()
    148   bool ok() const;
    149 
    150   // Returns a reference to our current value, or CHECK-fails if !this->ok().
    151   // If you need to initialize a T object from the stored value,
    152   // ConsumeValueOrDie() may be more efficient.
    153   const T& ValueOrDie() const;
    154 
    155  private:
    156   Status status_;
    157   T value_;
    158 };
    159 
    160 ////////////////////////////////////////////////////////////////////////////////
    161 // Implementation details for StatusOr<T>
    162 
    163 namespace internal {
    164 
    165 class LIBPROTOBUF_EXPORT StatusOrHelper {
    166  public:
    167   // Move type-agnostic error handling to the .cc.
    168   static void Crash(const util::Status& status);
    169 
    170   // Customized behavior for StatusOr<T> vs. StatusOr<T*>
    171   template<typename T>
    172   struct Specialize;
    173 };
    174 
    175 template<typename T>
    176 struct StatusOrHelper::Specialize {
    177   // For non-pointer T, a reference can never be NULL.
    178   static inline bool IsValueNull(const T& t) { return false; }
    179 };
    180 
    181 template<typename T>
    182 struct StatusOrHelper::Specialize<T*> {
    183   static inline bool IsValueNull(const T* t) { return t == NULL; }
    184 };
    185 
    186 }  // namespace internal
    187 
    188 template<typename T>
    189 inline StatusOr<T>::StatusOr()
    190     : status_(util::Status::UNKNOWN) {
    191 }
    192 
    193 template<typename T>
    194 inline StatusOr<T>::StatusOr(const Status& status) {
    195   if (status.ok()) {
    196     status_ = Status(error::INTERNAL, "Status::OK is not a valid argument.");
    197   } else {
    198     status_ = status;
    199   }
    200 }
    201 
    202 template<typename T>
    203 inline StatusOr<T>::StatusOr(const T& value) {
    204   if (internal::StatusOrHelper::Specialize<T>::IsValueNull(value)) {
    205     status_ = Status(error::INTERNAL, "NULL is not a vaild argument.");
    206   } else {
    207     status_ = Status::OK;
    208     value_ = value;
    209   }
    210 }
    211 
    212 template<typename T>
    213 inline StatusOr<T>::StatusOr(const StatusOr<T>& other)
    214     : status_(other.status_), value_(other.value_) {
    215 }
    216 
    217 template<typename T>
    218 inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<T>& other) {
    219   status_ = other.status_;
    220   value_ = other.value_;
    221   return *this;
    222 }
    223 
    224 template<typename T>
    225 template<typename U>
    226 inline StatusOr<T>::StatusOr(const StatusOr<U>& other)
    227     : status_(other.status_), value_(other.status_.ok() ? other.value_ : T()) {
    228 }
    229 
    230 template<typename T>
    231 template<typename U>
    232 inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<U>& other) {
    233   status_ = other.status_;
    234   if (status_.ok()) value_ = other.value_;
    235   return *this;
    236 }
    237 
    238 template<typename T>
    239 inline const Status& StatusOr<T>::status() const {
    240   return status_;
    241 }
    242 
    243 template<typename T>
    244 inline bool StatusOr<T>::ok() const {
    245   return status().ok();
    246 }
    247 
    248 template<typename T>
    249 inline const T& StatusOr<T>::ValueOrDie() const {
    250   if (!status_.ok()) {
    251     internal::StatusOrHelper::Crash(status_);
    252   }
    253   return value_;
    254 }
    255 }  // namespace util
    256 }  // namespace protobuf
    257 }  // namespace google
    258 
    259 #endif  // GOOGLE_PROTOBUF_STUBS_STATUSOR_H_
    260