text: /*    Copyright 2012 10gen Inc.
   *
   *    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
   *
   *    http://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.
   */
  
  #pragma once
  
  #include <iosfwd>
  #include <string>
  
  #include "mongo/base/error_codes.h"
  #include "mongo/platform/atomic_word.h"
  
  namespace mongo {
  
      /**
       * Status represents an error state or the absence thereof.
       *
       * A Status uses the standardized error codes -- from file 'error_codes.h' -- to
       * determine an error's cause. It further clarifies the error with a textual
       * description. Optionally, a Status may also have an error location number, which
       * should be a unique, grep-able point in the code base (including assert numbers).
       *
       * Example usage:
       *
       *    Status sumAB(int a, int b, int* c) {
       *       if (overflowIfSum(a,b)) {
       *           return Status(ErrorCodes::ERROR_OVERFLOW, "overflow in sumAB", 16494);
       *       }
       *
       *       *c = a+b;
       *       return Status::OK();
       *   }
       *
       * TODO: expand base/error_codes.h to capture common errors in current code
       * TODO: generate base/error_codes.h out of a description file
       * TODO: check 'location' duplicates against assert numbers
       */
      class Status {
      public:
          // Short-hand for returning an OK status.
          static Status OK() { return Status(getOKInfo()); }
  
          /**
           * Builds an error status given the error code, a textual description of what
           * caused the error, and a unique position in the where the error occurred
           * (similar to an assert number)
           */
          Status(ErrorCodes::Error code, const std::string& reason, int location = 0);
          Status(ErrorCodes::Error code, const char* reason, int location = 0);
          Status(const Status& other);
          Status& operator=(const Status& other);
          ~Status();
  
          /**
           * Returns true if 'other's error code and location are equal/different to this
           * instance's. Otherwise returns false.
           */
          bool compare(const Status& other) const;
          bool operator==(const Status& other) const;
          bool operator!=(const Status& other) const;
  
          /**
           * Returns true if 'other's error code is equal/different to this instance's.
           * Otherwise returns false.
           */
          bool compareCode(const ErrorCodes::Error other) const;
          bool operator==(const ErrorCodes::Error other) const;
          bool operator!=(const ErrorCodes::Error other) const;
  
          //
          // accessors
          //
  
          bool isOK() const { return code() == ErrorCodes::OK; }
          ErrorCodes::Error code() const { return _error->code; }
          const char* codeString() const { return ErrorCodes::errorString(_error->code); }
          const std::string& reason() const { return _error->reason; }
          int location() const { return _error->location; }
  
          std::string toString() const;
  
          //
          // Below interface used for testing code only.
          //
  
          int refCount() const { return _error->refs.load(); }
  
      private:
          struct ErrorInfo {
              AtomicUInt32 refs;       // reference counter
              ErrorCodes::Error code;  // error code
              std::string reason;      // description of error cause
              int location;            // unique location of the triggering line in the code
  
              ErrorInfo(ErrorCodes::Error aCode, const std::string& aReason, int aLocation);
          };
  
          static ErrorInfo *getOKInfo();
  
          explicit Status(ErrorInfo *info);
  
          ErrorInfo* _error;
  
          /**
           * Increment/Decrement the reference counter inside an ErrorInfo
           *
           * @param error  ErrorInfo to be incremented
           */
          static void ref(ErrorInfo* error);
          static void unref(ErrorInfo* error);
      };
  
      static inline bool operator==(const ErrorCodes::Error lhs, const Status& rhs) {
          return rhs == lhs;
      }
  
      static inline bool operator!=(const ErrorCodes::Error lhs, const Status& rhs) {
          return rhs != lhs;
      }
  
      //
      // Convenience method for unittest code. Please use accessors otherwise.
      //
  
      std::ostream& operator<<(std::ostream& os, const Status& status);
      std::ostream& operator<<(std::ostream& os, ErrorCodes::Error);
  
  }  // namespace mongo
  