#include <experimental/coroutine>
#include <iostream>
#include <stdint.h>
#include <stdio.h>
#include <Windows.h>
#include <string>

template<typename T>
struct sync 
{
	struct promise_type;
	using  handle_type = std::experimental::coroutine_handle<promise_type>;

	handle_type coro;

	sync(handle_type coro) : coro(coro)
	{
		std::cout << "Created a sync object" << std::endl;
	}

	sync(const sync<T> &s) = delete;

	sync(sync<T> &&s) : coro(s.coro)
	{
		std::cout << "Moved a sync object" << std::endl;
		s.coro = nullptr;
	}

	~sync() 
	{
		std::cout << "Sync gone" << std::endl;
		if(coro)
		{
			coro.destroy();
			coro = nullptr;
		}
	}

	T get() 
	{
		std::cout << "We got asked for the return value..." << std::endl;
		return coro.promise().value;
	}

	sync &operator = (const sync &) = delete;

	struct promise_type
	{
		T value;

		promise_type()
		{
			std::cout << "Promise created" << std::endl;
		}

		~promise_type()
		{
			std::cout << "Promise died" << std::endl;
		}

		sync<T> get_return_object()
		{
			std::cout << "Send back a sync" << std::endl;
			return sync<T>(handle_type::from_promise(*this));
		}

		auto initial_suspend()
		{
			std::cout << "Started the coroutine, don't stop now!" << std::endl;
			return std::experimental::suspend_never{};
		}

		auto return_value(T v)
		{
			std::cout << "Got an answer of " << v << std::endl;
			value = v;
			return std::experimental::suspend_never{};
		}

		auto final_suspend()
		{
			std::cout << "Finished the coro" << std::endl;
			return std::experimental::suspend_always{};
		}

		void unhandled_exception()
		{
			std::exit(1);
		}
	} type;
};

sync<int> answer()
{
	printf("Thinking...\n");
	co_return 42;
}

int main(int argc, char **argv)
{
	printf("Answer: %i\n", answer().get());

	system("PAUSE");
	return 0;
}