{"id":15047811,"url":"https://github.com/ivanpinezhaninov/async_promise","last_synced_at":"2026-04-08T14:31:44.428Z","repository":{"id":200589862,"uuid":"705518494","full_name":"IvanPinezhaninov/async_promise","owner":"IvanPinezhaninov","description":"C++11 header-only library based on Promises/A+","archived":false,"fork":false,"pushed_at":"2024-01-28T18:12:56.000Z","size":115,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-20T17:17:20.444Z","etag":null,"topics":["cplusplus","cplusplus-11","cpp","cpp11","header-only","promise","promise-a-plus","promise-all","promise-any","promise-aplus","promise-chain","promise-library"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/IvanPinezhaninov.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-10-16T07:07:57.000Z","updated_at":"2023-12-10T08:42:12.000Z","dependencies_parsed_at":null,"dependency_job_id":"dd148e7a-bc06-4aa8-b312-2913ab1b6aef","html_url":"https://github.com/IvanPinezhaninov/async_promise","commit_stats":null,"previous_names":["ivanpinezhaninov/async_promise"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IvanPinezhaninov%2Fasync_promise","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IvanPinezhaninov%2Fasync_promise/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IvanPinezhaninov%2Fasync_promise/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IvanPinezhaninov%2Fasync_promise/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/IvanPinezhaninov","download_url":"https://codeload.github.com/IvanPinezhaninov/async_promise/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243489778,"owners_count":20298997,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cplusplus","cplusplus-11","cpp","cpp11","header-only","promise","promise-a-plus","promise-all","promise-any","promise-aplus","promise-chain","promise-library"],"created_at":"2024-09-24T21:04:55.930Z","updated_at":"2025-12-29T14:14:20.753Z","avatar_url":"https://github.com/IvanPinezhaninov.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# async::promise\n\n[![Language C++11](https://img.shields.io/badge/language-C%2B%2B11-004482?style=flat-square\n)](https://isocpp.org/wiki/faq/cpp11) [![MIT License](https://img.shields.io/github/license/IvanPinezhaninov/async_promise?label=license\u0026style=flat-square)](http://opensource.org/licenses/MIT) [![Build status](https://img.shields.io/github/actions/workflow/status/IvanPinezhaninov/async_promise/build-and-test.yml?style=flat-square\n)](https://github.com/IvanPinezhaninov/async_promise/actions/workflows/build-and-test.yml) [![Codecov](https://img.shields.io/codecov/c/github/IvanPinezhaninov/async_promise?style=flat-square)](https://codecov.io/gh/IvanPinezhaninov/async_promise)\n\n## Overview\n\nC++11 header-only library based on Promises/A+\n\nThe library is designed to create and run a chain of functions or class methods. The chain runs asynchronously and returns `std::future`. The library supports the methods `resolve`, `reject`, `then`, `all`, `all_settled`, `any`, `race`, `fail` and `finally`\n\n## Documentation\n\nTo create an `async::promise` object use the static function `async::make_promise`, which takes as an argument a function with optional arguments\n```cpp\nauto promise = async::make_promise([] (int a, int b) { return a + b; }, 2, 2);\n```\n\nTo start the execution of a chain of function calls use the `run` method which returns `std::future`\n```cpp\nauto future = async::make_promise([] { return 2; }).run();\n\nstd::cout \u003c\u003c future.get() \u003c\u003c std::endl; // prints 2\n```\n\nTo add the next function to a chain use the `then` method which takes as an argument a function with an argument of the same type as the return value of the previous function in the chain\n```cpp\nauto future = async::make_promise([] { return 2; })\n              .then([] (int x) { return x * 2; })\n              .run();\n\nstd::cout \u003c\u003c future.get() \u003c\u003c std::endl; // prints 4\n```\n\nIf the `then` method does not need to process the value returned by the previous function, then it is allowed to pass a function that does not take an argument\n```cpp\nauto future = async::make_promise([] { return 2; })\n              .then([] { return 4; })\n              .run();\n\nstd::cout \u003c\u003c future.get() \u003c\u003c std::endl; // prints 4\n```\n\nThe `all` method accepts an iterable of functions. Each function asynchronously processes the return value of the previous function. When all functions have completed, the method will return an iterable with the results of functions in the same order as the functions in the incoming iterable. If an error occurs while executing functions it will be thrown\n```cpp\nstd::vector\u003cint(*)(int)\u003e funcs\n{\n  [] (int x) { return x * 2; },\n  [] (int x) { return x * 4; },\n};\n\nauto future = async::make_promise([] { return 2; })\n              .all(funcs)\n              .run();\n\nauto results = future.get();\nfor (const auto\u0026 result : results)\n  std::cout \u003c\u003c result \u003c\u003c std::endl;\n```\n\nIt is also possible to create a promise object using the static function `async::make_promise_all`\n```cpp\nstd::vector\u003cint(*)(int)\u003e funcs\n{\n  [] (int x) { return x * 2; },\n  [] (int x) { return x * 4; },\n};\n\nauto future = async::make_promise_all(funcs, 2)\n              .run();\n\nauto results = future.get();\nfor (const auto\u0026 result : results)\n  std::cout \u003c\u003c result \u003c\u003c std::endl;\n```\n\nThe `all_settled` method accepts an iterable of functions. Each function asynchronously processes the return value of the previous function. When all functions have completed, the method will return an iterable with a special `settled` object that contains either a result or an error of functions in the same order as the functions in the incoming iterable\n```cpp\nstd::vector\u003cint(*)(int)\u003e funcs\n{\n  [] (int x) { return x * 2; },\n  [] (int x) -\u003e int { throw std::runtime_error{\"I'm an error'\"}; },\n};\n\nauto future = async::make_promise([] { return 2; })\n              .all_settled(funcs)\n              .run();\n\nauto results = future.get();\nfor (const auto\u0026 result : results)\n{\n  switch (result.type)\n  {\n    case async::settle_type::resolved:\n      std::cout \u003c\u003c \"resolved: \" \u003c\u003c result.result \u003c\u003c std::endl;\n      break;\n    case async::settle_type::rejected:\n      try\n      {\n        std::rethrow_exception(result.error);\n      }\n      catch (const std::exception\u0026 e)\n      {\n        std::cout \u003c\u003c \"rejected: \" \u003c\u003c e.what() \u003c\u003c std::endl;\n      }\n      break;\n  }\n}\n```\n\nIt is also possible to create a promise object using the static function `async::make_promise_all_settled`\n```cpp\nstd::vector\u003cint(*)(int)\u003e funcs\n{\n  [] (int x) { return x * 2; },\n  [] (int x) -\u003e int { throw std::runtime_error{\"I'm an error'\"}; },\n};\n\nauto future = async::make_promise_all_settled(funcs, 2)\n              .run();\n\nauto results = future.get();\nfor (const auto\u0026 result : results)\n{\n  switch (result.type)\n  {\n    case async::settle_type::resolved:\n      std::cout \u003c\u003c \"resolved: \" \u003c\u003c result.result \u003c\u003c std::endl;\n      break;\n    case async::settle_type::rejected:\n      try\n      {\n        std::rethrow_exception(result.error);\n      }\n      catch (const std::exception\u0026 e)\n      {\n        std::cout \u003c\u003c \"rejected: \" \u003c\u003c e.what() \u003c\u003c std::endl;\n      }\n      break;\n  }\n}\n```\n\nThe `any` method accepts an iterable of functions. Each function asynchronously processes the return value of the previous function. The result of the method will be the result of the first function that completes successfully. If all functions fail, an `async::aggregate_error` exception will be thrown\n```cpp\nstd::vector\u003cint(*)(int)\u003e funcs\n{\n  [] (int x) -\u003e int { throw std::runtime_error{\"I'm an error'\"}; },\n  [] (int x) { return x * 2; },\n};\n\nauto future = async::make_promise([] { return 2; })\n              .any(funcs)\n              .run();\n\nstd::cout \u003c\u003c future.get() \u003c\u003c std::endl; // prints 4\n```\n\nIt is also possible to create a promise object using the static function `async::make_promise_any`\n```cpp\nstd::vector\u003cint(*)(int)\u003e funcs\n{\n  [] (int x) -\u003e int { throw std::runtime_error{\"I'm an error'\"}; },\n  [] (int x) { return x * 2; },\n};\n\nauto future = async::make_promise_any(funcs, 2)\n              .run();\n\nstd::cout \u003c\u003c future.get() \u003c\u003c std::endl; // prints 4\n```\n\nThe `race` method accepts an iterable of functions. Each function asynchronously processes the return value of the previous function. The result of the method will be the result or error of the first completed function\n```cpp\nstd::vector\u003cint(*)(int)\u003e funcs\n{\n  [] (int x) -\u003e int { throw std::runtime_error{\"I'm an error'\"}; },\n  [] (int x) { return x * 2; },\n};\n\nauto future = async::make_promise([] { return 2; })\n              .race(funcs)\n              .run();\n\ntry\n{\n  std::cout \u003c\u003c future.get() \u003c\u003c std::endl;\n}\ncatch (const std::exception\u0026 e)\n{\n  std::cout \u003c\u003c e.what() \u003c\u003c std::endl;\n}\n```\n\nIt is also possible to create a promise object using the static function `async::make_promise_race`\n```cpp\nstd::vector\u003cint(*)(int)\u003e funcs\n{\n  [] (int x) -\u003e int { throw std::runtime_error{\"I'm an error'\"}; },\n  [] (int x) { return x * 2; },\n};\n\nauto future = async::make_promise_race(funcs, 2)\n              .run();\n\ntry\n{\n  std::cout \u003c\u003c future.get() \u003c\u003c std::endl;\n}\ncatch (const std::exception\u0026 e)\n{\n  std::cout \u003c\u003c e.what() \u003c\u003c std::endl;\n}\n```\n\nIn the `all`, `all_settled`, `any` and `race` methods it is allowed to use iterable with functions without an argument if it is not necessary to process the value returned by the previous function\n```cpp\nstd::vector\u003cint(*)()\u003e funcs\n{\n  [] () { return 1; },\n  [] () { return 2; },\n};\n\nauto future = async::make_promise([] { return 2; })\n              .all(funcs)\n              .run();\n\nauto results = future.get();\nfor (const auto\u0026 result : results)\n  std::cout \u003c\u003c result \u003c\u003c std::endl;\n```\n\nCatching exceptions thrown in previously called functions is done by adding a `fail` method to the chain, which takes as an argument a function with an argument of type `std::exception_ptr` and returns a value of the same type as the previously called function. If the previous functions were executed without errors, then the method will return the result of the previous function\n```cpp\nstatic int error_handler(const std::exception_ptr\u0026 e)\n{\n  try\n  {\n    std::rethrow_exception(e);\n  }\n  catch(const std::exception\u0026 e)\n  {\n    return -1;\n  }\n  catch(...)\n  {\n    return -2;\n  }\n}\n\nauto future = async::make_promise([] { throw std::runtime_error{\"I'm an error!\"}; })\n              .fail(error_handler)\n              .run();\n\nstd::cout \u003c\u003c future.get() \u003c\u003c std::endl; // prints -1\n```\n\nIf the `fail` method does not need to handle a previously thrown exception, it is allowed to pass a function without an argument to the `fail` method\n```cpp\nstatic int error()\n{\n  throw std::runtime_error{\"I'm an error\"};\n}\n\nstatic int error_handler()\n{\n  return -1;\n}\n\nauto future = async::make_promise(error)\n              .fail(error_handler)\n              .run();\n\nstd::cout \u003c\u003c future.get() \u003c\u003c std::endl; // prints -1\n```\n\nTo add the next function to a chain that will be called on both resolved and rejected states, use the `finally` method\n```cpp\nauto future1 = async::make_promise([] {})\n               .finally([] { return \"Hello World!\"; })\n               .run();\n\nauto future2 = async::make_promise([] { throw std::runtime_error{\"I'm an error!\"}; })\n               .finally([] { return \"Hello World!\"; })\n               .run();\n\nstd::cout \u003c\u003c future1.get() \u003c\u003c std::endl; // prints \"Hello World!\"\nstd::cout \u003c\u003c future2.get() \u003c\u003c std::endl; // prints \"Hello World!\"\n```\n\nIn all the above cases, you can use overloaded functions that take a class method or an iterable of class methods and a class object\n```cpp\nmy_class obj;\n\nstd::vector\u003cint(my_class::*)(int)\u003e all_methods\n{\n  \u0026my_class::method1,\n  \u0026my_class::method2,\n};\n\nauto future = async::make_promise(\u0026my_class::method, \u0026obj)\n              .then(\u0026my_class::then_method, \u0026obj)\n              .all(std::move(all_methods), \u0026obj)\n              .run();\n```\n\nTo create `async::promise` object with resolved state, use the `async::make_resolved_promise` static function\n```cpp\nauto future = async::make_resolved_promise(2)\n              .run();\n\nstd::cout \u003c\u003c future.get() \u003c\u003c std::endl; // prints 2\n```\n\nTo create `async::promise` object with rejected state, use the `async::make_rejected_promise` static function\n```cpp\nauto future = async::make_rejected_promise\u003cint\u003e(std::runtime_error{\"I'm an error!\"})\n              .run();\n\ntry\n{\n  std::cout \u003c\u003c future.get() \u003c\u003c std::endl;\n}\ncatch (const std::runtime_error\u0026 e)\n{\n  std::cout \u003c\u003c e.what() \u003c\u003c std::endl;\n}\n```\n\n## Build and test\n\n```bash\ngit clone https://github.com/IvanPinezhaninov/async_promise.git\ncd async_promise\nmkdir build\ncd build\ncmake -GNinja .. -DCMAKE_BUILD_TYPE=Release -DASYNC_PROMISE_BUILD_TESTS=YES\ncmake --build . -- -j4\nctest\n```\n\n## License\nThis code is distributed under the [MIT License](LICENSE)\n\n## Author\n[Ivan Pinezhaninov](mailto:ivan.pinezhaninov@gmail.com)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fivanpinezhaninov%2Fasync_promise","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fivanpinezhaninov%2Fasync_promise","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fivanpinezhaninov%2Fasync_promise/lists"}