#ifndef __VEREIGN_CORE_RVREF_HH
#define __VEREIGN_CORE_RVREF_HH

namespace vereign {
namespace core {

#ifdef __WINDOWS__
#pragma warning(push)
#pragma warning(disable: 4521)
#endif

/**
 * Rvalue reference wrapper.
 *
 * Wraps rvalue reference in copyable object.
 * Thus allowing lambda to capture rvalue references.
 *
 * @code
 * std::string foo = "foo";
 * auto foo_ref MakeRvRef(foo);
 * auto lambda = [foo_ref] () mutable {
 *   std::cout << foo_ref.get() << std::endl;
 * };
 * lambda();
 * @endcode
 *
 */
template <typename T>
class RvRef {
public:
  RvRef() = delete;
  RvRef& operator=(RvRef& other) = delete;

  RvRef(T&& value) : value_{std::move(value)} {}
  RvRef(RvRef& other) : value_{std::move(other.value_)} {}
  RvRef(RvRef&& other) : value_{std::move(other.value_)} {}

  /**
   * Retrieve reference to the stored value.
   */
  const T& Get() const noexcept {
    return value_;
  }

  /**
   * Retrieve reference to the stored value.
   */
  T& Get() noexcept {
    return value_;
  }

  /**
   * Retrieve reference to the stored value.
   */
  const T* operator->() const noexcept {
    return &value_;
  }

  /**
   * Retrieve reference to the stored value.
   */
  T* operator->() noexcept {
    return &value_;
  }

private:
  T value_;
};

#ifdef __WINDOWS__
#pragma warning(pop)
#endif

template <typename T>
RvRef<T> MakeRvRef(T&& value) {
  return RvRef<T>(std::move(value));
}

}
}

#endif