#ifndef TILE_BASE_FUTURE_PROMISE_H
#define TILE_BASE_FUTURE_PROMISE_H

#pragma once

#include "tile/base/future/basic.h"
#include "tile/base/future/core.h"

namespace tile {
namespace future {

template<typename... Ts>
class Promise {
public:
    using value_type = std::tuple<Ts...>;

    Promise();
    // Non-copyable
    Promise(const Promise &)            = delete;
    Promise &operator=(const Promise &) = delete;

    // Movable.
    Promise(Promise &&)            = default;
    Promise &operator=(Promise &&) = default;

    static_assert(!types_contains<Types<Ts...>, void>::value,
                  "There's no point in specifying `void` in `Ts...`, use "
                  "`Promise<>` if you meant to declare a future with no value.");

    Future<Ts...> GetFuture();
    template<typename... Us, typename = enable_if_t<std::is_constructible<value_type, Us &&...>::value>>
    void SetValue(Us &&...values);

    void SetBoxed(Boxed<Ts...> boxed);

private:
    template<typename... Us>
    friend class Future;

    explicit Promise(Executor executor);
    std::shared_ptr<Core<Ts...>> core_;
};

}// namespace future
}// namespace tile

#endif// TILE_BASE_FUTURE_PROMISE_H
