Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

feat: coroutines, still experimental but useable #724

Merged
merged 6 commits into from
Jul 19, 2023

Conversation

Mishura4
Copy link
Member

@Mishura4 Mishura4 commented Jul 10, 2023

It's here! The rewrite of DPP's coroutines. Now supports :

  • The task object going out of scope (e.g. starting a coroutine in an event callback and returning). The promise detaches itself and will handle its own destruction at the end of the coroutine
  • Nested tasks, theoretically infinite levels of nesting (until out of memory)
  • dpp::awaitable is now generic and can be used to wrap any function whose signature ends with a callback :
    • co_await dpp::awaitable{interaction, &dpp::interaction_create_t::get_original_response};
    • co_await dpp::awaitable<http_request_completion_t>{[&](auto &&callback) { cluster->request(url, method, callback, postdata, mimetype, headers); }};
  • API calls are sent immediately on creation of the awaitable so a user can start a few and wait for all of them in one go later

Example :

_bot->on_message_create.co_attach([](const dpp::message_create_t& e) -> dpp::task<void> { // Tasks attached to an event are void return only
	// Make a nested task which will return a boolean (or any other type). Not necessary, this is to show nested tasks
	// Very advised to take any variables by parameter and not by capture - this way if the lambda goes out of scope but the task keeps running, the variables are still valid due to being on the coroutine stack frame
	auto nested_task = [](dpp::cluster *cluster, dpp::message event) -> dpp::task<bool> {
		// Create a message and wait for the API response
		dpp::confirmation_callback_t confirm = co_await cluster->co_message_create(dpp::message{"Retrieving emoji list"}.set_channel_id(event.channel_id));

		// Retrieve the dpp::message returned by the API
		dpp::message original = confirm.get<dpp::message>();

		// Get the emoji list from the guild and wait for the API response
		confirm = co_await cluster->co_guild_emojis_get(event.guild_id);

		// Get the dpp::emoji_map from the API response
		const auto &map = confirm.get<dpp::emoji_map>();
		int i = 0;
		for (auto it = map.begin(); it != map.end() && i < 5; ++i) { // List the 50 first emoji found, 10 per message
			dpp::message message{fmt::format("{}", fmt::join(
				std::ranges::views::iota(it, map.end()) // C++20 flex 😎
				| std::ranges::views::transform([](auto &&elem){ return (elem->second.get_mention()); })
				| std::ranges::views::take(10),
			" "))};

			// Create the message and wait for the API response
			co_await cluster->co_message_create(message.set_channel_id(event.channel_id));
			std::ranges::advance(it, 10, map.end());
		}
		co_return true;
	};
	// Wait for the whole thing to finish - for example you may want to do something else after with the result, maybe another nested task
	bool success = co_await nested_task(e.from->creator, e.msg);
}

Output:
Example output of the code above

✅Thoroughly tested on MSVC 19.37.32705 and g++ 13.1, works like a charm, no leaks, no crashes during intended usage.
⚠NOT tested on clang. Currently coroutines are still labelled as "experimental" on clang, and require using libc++. If anyone wants to test it, that would be really appreciated.

@netlify
Copy link

netlify bot commented Jul 10, 2023

Deploy Preview for dpp-dev ready!

Name Link
🔨 Latest commit eb7a8c5
🔍 Latest deploy log https://app.netlify.com/sites/dpp-dev/deploys/64b5b4806067c400083476bb
😎 Deploy Preview https://deploy-preview-724--dpp-dev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@Mishura4 Mishura4 force-pushed the coroutines_pr branch 5 times, most recently from ddbd176 to 64a4baf Compare July 11, 2023 02:59
@Mishura4 Mishura4 marked this pull request as draft July 11, 2023 03:45
@Mishura4
Copy link
Member Author

Need to keep tweaking the docs, especially formatting, which I will do within the next few days

@Mishura4 Mishura4 changed the title feat: coroutines, now useable feat: coroutines, still experimental but useable Jul 11, 2023
@Mishura4 Mishura4 force-pushed the coroutines_pr branch 4 times, most recently from c7aeb05 to 0a0192d Compare July 15, 2023 00:05
@Mishura4 Mishura4 marked this pull request as ready for review July 15, 2023 00:22
@Mishura4 Mishura4 marked this pull request as draft July 15, 2023 03:26
@Mishura4 Mishura4 force-pushed the coroutines_pr branch 5 times, most recently from b56918c to 864ee00 Compare July 16, 2023 04:48
@Mishura4 Mishura4 marked this pull request as ready for review July 16, 2023 06:53
@Mishura4
Copy link
Member Author

👍

Mishura4 added 2 commits July 16, 2023 03:42
…, support destroyed awaitable on API response, fix potential race condition between task and promise destructors
@braindigitalis braindigitalis self-requested a review July 16, 2023 13:52
@braindigitalis braindigitalis merged commit a33ecb5 into brainboxdotcc:dev Jul 19, 2023
@Commandserver Commandserver added the enhancement New feature or request label Jul 27, 2023
@Mishura4 Mishura4 deleted the coroutines_pr branch August 8, 2023 20:11
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants