<commit_before>#pragma once
/*
**  Copyright (C) 2013 <NAME>
**  See COPYING for the license
*/

#ifndef QI_TYPE_DETAIL_FUTURE_ADAPTER_HXX_
#define QI_TYPE_DETAIL_FUTURE_ADAPTER_HXX_

#include <boost/scope_exit.hpp>

#include <qi/type/detail/futureadapter.hpp>

namespace qi
{
namespace detail
{

static const char* InvalidValueError = "value is invalid";
static const char* InvalidFutureError = "function returned an invalid future";

template<typename T> void setPromise(qi::Promise<T>& promise, const AnyValue& v)
{
  if (!v.isValid())
  {
    promise.setError(InvalidValueError);
    return;
  }

  try
  {
    qiLogDebug("qi.adapter") << "converting value";
    T val = v.to<T>();
    qiLogDebug("qi.adapter") << "setting promise";
    promise.setValue(val);
    qiLogDebug("qi.adapter") << "done";
  }
  catch(const std::exception& e)
  {
    qiLogError("qi.adapter") << "future to promise forwarding error: " << e.what();
    promise.setError(e.what());
  }
}

template<> inline void setPromise(qi::Promise<void>& promise, const AnyValue&)
{
  promise.setValue(0);
}

template<> inline void setPromise(qi::Promise<AnyValue>& promise, const AnyValue& val)
{
  promise.setValue(val);
}

template<> inline void setPromise(qi::Promise<AnyReference>& promise, const AnyValue& val)
{
  promise.setValue(val.clone());
}

template <typename T>
void futureAdapterGeneric(AnyReference val, qi::Promise<T> promise,
    boost::shared_ptr<GenericObject>& ao)
{
  if (!val.isValid())
  {
    promise.setError(InvalidValueError);
    return;
  }

  QI_ASSERT(ao);
  qiLogDebug("qi.adapter") << "futureAdapter trigger";
  TypeOfTemplate<Future>* ft1 = QI_TEMPLATE_TYPE_GET(val.type(), Future);
  TypeOfTemplate<FutureSync>* ft2 = QI_TEMPLATE_TYPE_GET(val.type(), FutureSync);
  qiLogDebug("qi.adapter") << "isFuture " << val.type()->infoString() << ' ' << !!ft1 << ' ' << !!ft2;
  bool isvoid = false;
  if (ft1)
    isvoid = ft1->templateArgument()->kind() == TypeKind_Void;
  else if (ft2)
    isvoid = ft2->templateArgument()->kind() == TypeKind_Void;
  GenericObject& gfut = *ao;
  // reset the shared_ptr to break the cycle
  BOOST_SCOPE_EXIT_TPL(&ao, &val) {
    ao.reset();
    val.destroy();
  } BOOST_SCOPE_EXIT_END
  if (gfut.call<bool>("hasError", 0))
  {
    qiLogDebug("qi.adapter") << "futureAdapter: future in error";
    std::string s = gfut.call<std::string>("error", 0);
    qiLogDebug("qi.adapter") << "futureAdapter: got error: " << s;
    promise.setError(s);
    return;
  }
  if (gfut.call<bool>("isCanceled"))
  {
    qiLogDebug("qi.adapter") << "futureAdapter: future canceled";
    promise.setCanceled();
    return;
  }
  qiLogDebug("qi.adapter") << "futureAdapter: future has value";
  AnyValue v = gfut.call<AnyValue>("value", 0);
  // For a Future<void>, value() gave us a void*
  if (isvoid)
    v = AnyValue(qi::typeOf<void>());
  qiLogDebug("qi.adapter") << (v.isValid() ? v.type()->infoString() : "<invalid AnyValue>");
  setPromise(promise, v);
  qiLogDebug("qi.adapter") << "Promise set";
}

// return a generic object pointing to the future referenced by val or null if val is not a future
// remember that you need a shared_ptr pointing on the genericobject so that it can work (shared_from_this)
inline boost::shared_ptr<GenericObject> getGenericFuture(AnyReference val, TypeKind* kind = 0)
{
  if (!val.isValid())
  {
    qiLogDebug("qi.adapter") << "getGenericFuture: Invalid value.";
    return boost::shared_ptr<GenericObject>();
  }

  TypeOfTemplate<Future>* ft1 = QI_TEMPLATE_TYPE_GET(val.type(), Future);
  TypeOfTemplate<FutureSync>* ft2 = QI_TEMPLATE_TYPE_GET(val.type(), FutureSync);
  ObjectTypeInterface* onext = NULL;
  qiLogDebug("qi.adapter") << "isFuture " << val.type()->infoString() << ' ' << !!ft1 << ' ' << !!ft2;
  if (ft1)
  {
    if (kind)
      *kind = ft1->templateArgument()->kind();
    onext = ft1;
  }
  else if (ft2)
  {
    if (kind)
      *kind = ft2->templateArgument()->kind();
    onext = ft2;
  }
  if (!onext)
    return boost::shared_ptr<GenericObject>();
  return boost::make_shared<GenericObject>(onext, val.rawValue());
}

// futureAdapter helper that detects and handles value of kind future
// return true if value was a future and was handled
template <typename T>
inline bool handleFuture(AnyReference val, Promise<T> promise)
{
  boost::shared_ptr<GenericObject> ao = getGenericFuture(val);
  if (!ao)
    return false;

  if (!ao->call<bool>("isValid"))
  {
    promise.setError(InvalidFutureError);
    return true;
  }

  boost::function<void()> cb =
    boost::bind(futureAdapterGeneric<T>, val, promise, ao);
  // Careful, gfut will die at the end of this block, but it is
  // stored in call data. So call must finish before we exit this block,
  // and thus must be synchronous.
  try
  {
    ao->call<void>("_connect", cb);
    promise.setOnCancel(
        qi::bindSilent(
          static_cast<void(GenericObject::*)(const std::string&)>(
            &GenericObject::call<void>),
          boost::weak_ptr<GenericObject>(ao),
          "cancel"));
  }
  catch (std::exception& e)
  {
    qiLogError("qi.object") << "future connect error " << e.what();
    promise.setError("internal error: cannot connect returned future");
  }
  return true;
}

template <typename T>
inline T extractFuture(const qi::Future<qi::AnyReference>& metaFut)
{
  auto val = UniqueAnyReference{ metaFut.value() };
  if (!val->isValid())
    throw std::runtime_error(InvalidValueError);


  AnyValue hold;
  if (boost::shared_ptr<GenericObject> ao = getGenericFuture(*val))
  {
    if (!ao->call<bool>("isValid"))
      throw std::runtime_error(InvalidFutureError);

    hold = ao->call<qi::AnyValue>("value", (int)FutureTimeout_Infinite);
    *val = hold.asReference();
  }

  static TypeInterface* targetType;
  QI_ONCE(targetType = typeOf<T>());
  try
  {
    auto conv = val->convert(targetType);
    if (!conv->type())
      throw std::runtime_error(std::string("Unable to convert call result to target type: from ") +
                               val->signature(true).toPrettySignature() + " to " +
                               targetType->signature().toPrettySignature());
    return std::move(*conv->ptr<T>(false));
  }
  catch(const std::exception& e)
  {
    throw std::runtime_error(std::string("Return argument conversion error: ") + e.what());
  }
}

template <>
inline void extractFuture<void>(const qi::Future<qi::AnyReference>& metaFut)
{
  auto val = UniqueAnyReference{ metaFut.value() };
  if (!val->isValid())
    throw std::runtime_error(InvalidValueError);

  if (boost::shared_ptr<GenericObject> ao = getGenericFuture(*val))
  {
    if (!ao->call<bool>("isValid"))
      throw std::runtime_error(InvalidFutureError);

    ao->call<qi::AnyValue>("value", (int)FutureTimeout_Infinite);
  }
}

/// Factorization of the setting of the promise according to the future result.
template <typename T>
inline void setAdaptedResult(Promise<T>& promise, AnyReference& ref)
{
  if (!ref.isValid())
  {
    promise.setError(InvalidValueError);
    return;
  }

  static TypeInterface* targetType;
  QI_ONCE(targetType = typeOf<T>());
  try
  {
    auto conv = ref.convert(targetType);
    if (!conv->type())
      promise.setError(std::string("Unable to convert call result to target type: from ")
        + ref.signature(true).toPrettySignature() + " to " + targetType->signature().toPrettySignature() );
    else
    {
      promise.setValue(*conv->ptr<T>(false));
    }
  }
  catch(const std::exception& e)
  {
    promise.setError(std::string("Return argument conversion error: ") + e.what());
  }
  ref.destroy();
}

/// Specialization for setting the promise according to the future result in the case of void.
template <>
inline void setAdaptedResult<void>(Promise<void>& promise, AnyReference& ref)
{
  promise.setValue(nullptr);
  ref.destroy();
}

/// Specialization for setting the promise according to the future result in the case of AnyReference.
template <>
inline void setAdaptedResult<AnyReference>(Promise<AnyReference>& promise, AnyReference& ref)
{
  try
  {
    promise.setValue(ref.clone());
  }
  catch(const std::exception& e)
  {
    promise.setError(std::string("Return argument conversion error: ") + e.what());
  }
  ref.destroy();
}

template <typename T>
inline void futureAdapter(const qi::Future<qi::AnyReference>& metaFut, qi::Promise<T> promise)
{
  //error handling
  if (metaFut.hasError()) {
    promise.setError(metaFut.error());
    return;
  }
  if (metaFut.isCanceled()) {
    promise.setCanceled();
    return;
  }

  auto val = UniqueAnyReference{ metaFut.value(), DeferOwnership{} };
  if (handleFuture(*val, promise)) // handleFuture takes ownership of the value if it succeeds.
    return;
  val.takeOwnership();
  setAdaptedResult(promise, *val);
}

template <typename T>
inline void futureAdapterVal(const qi::Future<qi::AnyValue>& metaFut, qi::Promise<T> promise)
{<commit_msg>future: Clarifies ownership of AnyReferences in future adaptation functions.<commit_after>#pragma once
/*
**  Copyright (C) 2013 <NAME>ics
**  See COPYING for the license
*/

#ifndef QI_TYPE_DETAIL_FUTURE_ADAPTER_HXX_
#define QI_TYPE_DETAIL_FUTURE_ADAPTER_HXX_

#include <qi/type/detail/futureadapter.hpp>

namespace qi
{
namespace detail
{

static const char* InvalidValueError = "value is invalid";
static const char* InvalidFutureError = "function returned an invalid future";

template<typename T> void setPromise(qi::Promise<T>& promise, const AnyValue& v)
{
  if (!v.isValid())
  {
    promise.setError(InvalidValueError);
    return;
  }

  try
  {
    qiLogDebug("qi.adapter") << "converting value";
    T val = v.to<T>();
    qiLogDebug("qi.adapter") << "setting promise";
    promise.setValue(val);
    qiLogDebug("qi.adapter") << "done";
  }
  catch(const std::exception& e)
  {
    qiLogError("qi.adapter") << "future to promise forwarding error: " << e.what();
    promise.setError(e.what());
  }
}

template<> inline void setPromise(qi::Promise<void>& promise, const AnyValue&)
{
  promise.setValue(0);
}

template<> inline void setPromise(qi::Promise<AnyValue>& promise, const AnyValue& val)
{
  promise.setValue(val);
}

template<> inline void setPromise(qi::Promise<AnyReference>& promise, const AnyValue& val)
{
  promise.setValue(val.clone());
}

template <typename T>
void futureAdapterGeneric(AnyReference val, qi::Promise<T> promise,
    boost::shared_ptr<GenericObject> ao)
{
  if (!val.isValid())
  {
    promise.setError(InvalidValueError);
    return;
  }

  QI_ASSERT(ao);
  qiLogDebug("qi.adapter") << "futureAdapter trigger";
  TypeOfTemplate<Future>* ft1 = QI_TEMPLATE_TYPE_GET(val.type(), Future);
  TypeOfTemplate<FutureSync>* ft2 = QI_TEMPLATE_TYPE_GET(val.type(), FutureSync);
  qiLogDebug("qi.adapter") << "isFuture " << val.type()->infoString() << ' ' << !!ft1 << ' ' << !!ft2;
  bool isvoid = false;
  if (ft1)
    isvoid = ft1->templateArgument()->kind() == TypeKind_Void;
  else if (ft2)
    isvoid = ft2->templateArgument()->kind() == TypeKind_Void;
  GenericObject& gfut = *ao;
  if (gfut.call<bool>("hasError", 0))
  {
    qiLogDebug("qi.adapter") << "futureAdapter: future in error";
    std::string s = gfut.call<std::string>("error", 0);
    qiLogDebug("qi.adapter") << "futureAdapter: got error: " << s;
    promise.setError(s);
    return;
  }
  if (gfut.call<bool>("isCanceled"))
  {
    qiLogDebug("qi.adapter") << "futureAdapter: future canceled";
    promise.setCanceled();
    return;
  }
  qiLogDebug("qi.adapter") << "futureAdapter: future has value";
  AnyValue v = gfut.call<AnyValue>("value", 0);
  // For a Future<void>, value() gave us a void*
  if (isvoid)
    v = AnyValue(qi::typeOf<void>());
  qiLogDebug("qi.adapter") << (v.isValid() ? v.type()->infoString() : "<invalid AnyValue>");
  setPromise(promise, v);
  qiLogDebug("qi.adapter") << "Promise set";
}

// return a generic object pointing to the future referenced by val or null if val is not a future
// remember that you need a shared_ptr pointing on the genericobject so that it can work (shared_from_this)
inline boost::shared_ptr<GenericObject> getGenericFuture(AnyReference val, TypeKind* kind = 0)
{
  if (!val.isValid())
  {
    qiLogDebug("qi.adapter") << "getGenericFuture: Invalid value.";
    return boost::shared_ptr<GenericObject>();
  }

  TypeOfTemplate<Future>* ft1 = QI_TEMPLATE_TYPE_GET(val.type(), Future);
  TypeOfTemplate<FutureSync>* ft2 = QI_TEMPLATE_TYPE_GET(val.type(), FutureSync);
  ObjectTypeInterface* onext = NULL;
  qiLogDebug("qi.adapter") << "isFuture " << val.type()->infoString() << ' ' << !!ft1 << ' ' << !!ft2;
  if (ft1)
  {
    if (kind)
      *kind = ft1->templateArgument()->kind();
    onext = ft1;
  }
  else if (ft2)
  {
    if (kind)
      *kind = ft2->templateArgument()->kind();
    onext = ft2;
  }
  if (!onext)
    return boost::shared_ptr<GenericObject>();
  return boost::make_shared<GenericObject>(onext, val.rawValue());
}

// futureAdapter helper that detects and handles value of kind future
// return true if value was a future and was handled
// Takes ownership of the value if it returns true.
template <typename T>
inline bool handleFuture(AnyReference val, Promise<T> promise)
{
  boost::shared_ptr<GenericObject> ao = getGenericFuture(val);
  if (!ao)
    return false;

  // At this point, we are sure that the value holds a Future, so we take its ownership.
  UniqueAnyReference uval{ val };
  if (!ao->call<bool>("isValid"))
  {
    promise.setError(InvalidFutureError);
    return true;
  }

  // The callback takes ownership of the value. After that, the old reference will be in a invalid
  // state.
  // TODO: Remove use of a shared_ptr once we can initialize captures of the lambda (C++14).
  auto spVal = std::make_shared<UniqueAnyReference>(std::move(uval));
  boost::function<void()> cb = [=]() mutable {
      if (!spVal || !(*spVal)->isValid() || !ao)
        throw std::logic_error{"Future is either invalid or has already been adapted."};

      // Transfer the value to a local UniqueAnyReference.
      // Also reset the shared ptr to break the cycle.
      auto localRef = ka::exchange(spVal, nullptr);
      futureAdapterGeneric<T>(**localRef, promise, ka::exchange(ao, nullptr));
    };
  spVal.reset();

  // Careful, gfut will die at the end of this block, but it is
  // stored in call data. So call must finish before we exit this block,
  // and thus must be synchronous.
  try
  {
    ao->call<void>("_connect", cb);
    promise.setOnCancel(
        qi::bindSilent(
          static_cast<void(GenericObject::*)(const std::string&)>(
            &GenericObject::call<void>),
          boost::weak_ptr<GenericObject>(ao),
          "cancel"));
  }
  catch (std::exception& e)
  {
    qiLogError("qi.object") << "future connect error " << e.what();
    promise.setError("internal error: cannot connect returned future");
  }
  return true;
}

template <typename T>
inline T extractFuture(const qi::Future<qi::AnyReference>& metaFut)
{
  auto val = UniqueAnyReference{ metaFut.value() };
  if (!val->isValid())
    throw std::runtime_error(InvalidValueError);


  AnyValue hold;
  if (boost::shared_ptr<GenericObject> ao = getGenericFuture(*val))
  {
    if (!ao->call<bool>("isValid"))
      throw std::runtime_error(InvalidFutureError);

    hold = ao->call<qi::AnyValue>("value", (int)FutureTimeout_Infinite);
    *val = hold.asReference();
  }

  static TypeInterface* targetType;
  QI_ONCE(targetType = typeOf<T>());
  try
  {
    auto conv = val->convert(targetType);
    if (!conv->type())
      throw std::runtime_error(std::string("Unable to convert call result to target type: from ") +
                               val->signature(true).toPrettySignature() + " to " +
                               targetType->signature().toPrettySignature());
    return std::move(*conv->ptr<T>(false));
  }
  catch(const std::exception& e)
  {
    throw std::runtime_error(std::string("Return argument conversion error: ") + e.what());
  }
}

template <>
inline void extractFuture<void>(const qi::Future<qi::AnyReference>& metaFut)
{
  auto val = UniqueAnyReference{ metaFut.value() };
  if (!val->isValid())
    throw std::runtime_error(InvalidValueError);

  if (boost::shared_ptr<GenericObject> ao = getGenericFuture(*val))
  {
    if (!ao->call<bool>("isValid"))
      throw std::runtime_error(InvalidFutureError);

    ao->call<qi::AnyValue>("value", (int)FutureTimeout_Infinite);
  }
}

/// Factorization of the setting of the promise according to the future result.
/// This method takes ownership of the reference.
template <typename T>
inline void setAdaptedResult(Promise<T>& promise, UniqueAnyReference ref)
{
  if (!ref->isValid())
  {
    promise.setError(InvalidValueError);
    return;
  }

  static TypeInterface* targetType;
  QI_ONCE(targetType = typeOf<T>());
  try
  {
    auto conv = ref->convert(targetType);
    if (!conv->type())
      promise.setError(std::string("Unable to convert call result to target type: from ")
        + ref->signature(true).toPrettySignature() + " to " + targetType->signature().toPrettySignature() );
    else
    {
      promise.setValue(*conv->ptr<T>(false));
    }
  }
  catch(const std::exception& e)
  {
    promise.setError(std::string("Return argument conversion error: ") + e.what());
  }
}

/// Specialization for setting the promise according to the future result in the case of void.
/// This method takes ownership of the reference.
template <>
inline void setAdaptedResult<void>(Promise<void>& promise, UniqueAnyReference)
{
  promise.setValue(nullptr);
}

/// Specialization for setting the promise according to the future result in the case of AnyReference.
/// This method takes ownership of the reference.
template <>
inline void setAdaptedResult<AnyReference>(Promise<AnyReference>& promise, UniqueAnyReference ref)
{
  try
  {
    promise.setValue(ref->clone());
  }
  catch(const std::exception& e)
  {
    promise.setError(std::string("Return argument conversion error: ") + e.what());
  }
}

template <typename T>
inline void futureAdapter(const qi::Future<qi::AnyReference>& metaFut, qi::Promise<T> promise)
{
  //error handling
  if (metaFut.hasError()) {
    promise.setError(metaFut.error());
    return;
  }
  if (metaFut.isCanceled()) {
    promise.setCanceled();
    return;
  }

  auto val = metaFut.value();
  if (handleFuture(val, promise)) // Takes ownership of the value if it returns true.
    return;
  setAdaptedResult(promise, UniqueAnyReference{ val });
}

template <typename T>
inline void futureAdapterVal(const qi::Future<qi::AnyValue>& metaFut, qi::Promise<T> promise)
{
{'fraction_non_alphanumeric': 0.15003500457752167, 'fraction_numerical': 0.003015778986482848, 'mean_word_length': 4.118522601984565, 'pattern_counts': {'":': 0, '<': 253, '<?xml version=': 0, '>': 200, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2741413', 'n_tokens_mistral': 6042, 'n_tokens_neox': 5960, 'n_words': 1452}