// ========================================================= //
//                                                           //
//   File      : ErrorOrType.h                               //
//   Purpose   : provide "hybrid" result type                //
//                                                           //
//   Coded by Ralf Westram (coder@reallysoft.de) in Apr 19   //
//   http://www.arb-home.de/                                 //
//                                                           //
// ========================================================= //

#ifndef ERRORORTYPE_H
#define ERRORORTYPE_H

#ifndef ARB_ERROR_H
#include "arb_error.h"
#endif

template<typename TYPE>
class ErrorOr {
    /*! "hybrid" result type: is either an error or a value.
     * Note: TYPE has to be copyable!
     *       You have to use getError() or getValue() before an instance is destroyed!
     */

    // unittest at ../SL/HEADERTESTS/test_arb_error.cxx@TEST_ErrorOr
    ARB_ERROR error;
    TYPE      value;

#if defined(ASSERTION_USED)
    mutable bool checked;
#endif

    void mark_checked() const {
#if defined(ASSERTION_USED)
        checked = true;
#endif
    }
    void expect_checked() const { arb_assert(checked); }

public:
    ErrorOr(ARB_ERROR err, const TYPE& t) :
        error(err),
        value(t)
#if defined(ASSERTION_USED)
        , checked(false)
#endif
    {
    }

    bool hasError() const { mark_checked(); return error; }
    bool hasValue() const { return !hasError(); }

    ARB_ERROR getError() const { // may only be used once!
        expect_checked();
        arb_assert(hasError());
        return error;
    }
    TYPE getValue() const { // may only be used once!
        expect_checked();
        arb_assert(hasValue());
        error.expect_no_error();
        return value;
    }
};

#else
#error ErrorOrType.h included twice
#endif // ERRORORTYPE_H
