Skip to content
New issue

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

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

Already on GitHub? Sign in 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
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

👍

…, support destroyed awaitable on API response, fix potential race condition between task and promise destructors
@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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants