verdnatura-chat/ios/Pods/Flipper-Folly/folly/futures/Future.h

2694 lines
88 KiB
C
Raw Normal View History

Merge beta into master (#2143) * [FIX] Messages being sent but showing as temp status (#1469) * [FIX] Missing messages after reconnect (#1470) * [FIX] Few fixes on themes (#1477) * [I18N] Missing German translations (#1465) * Missing German translation * adding a missing space behind colon * added a missing space after colon * and another attempt to finally fix this – got confused by all the branches * some smaller fixes for the translation * better wording * fixed another typo * [FIX] Crash while displaying the attached image with http on file name (#1401) * [IMPROVEMENT] Tap app and server version to copy to clipboard (#1425) * [NEW] Reply notification (#1448) * [FIX] Incorrect background color login on iPad (#1480) * [FIX] Prevent multiple tap on send (Share Extension) (#1481) * [NEW] Image Viewer (#1479) * [DOCS] Update Readme (#1485) * [FIX] Jitsi with Hermes Enabled (#1523) * [FIX] Draft messages not working with themed Messagebox (#1525) * [FIX] Go to direct message from members list (#1519) * [FIX] Make SAML wait for idp token instead of creating it on client (#1527) * [FIX] Server Test Push Notification (#1508) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [CHORE] Update to new server response (#1509) * [FIX] Insert messages with blank users (#1529) * Bump version to 4.2.1 (#1530) * [FIX] Error when normalizing empty messages (#1532) * [REGRESSION] CAS (#1570) * Bump version to 4.2.2 (#1571) * [FIX] Add username block condition to prevent error (#1585) * Bump version to 4.2.3 * Bump version to 4.2.4 * Bump version to 4.3.0 (#1630) * [FIX] Channels doesn't load (#1586) * [FIX] Channels doesn't load * [FIX] Update roomsUpdatedAt when subscriptions.length is 0 * [FIX] Remove unnecessary changes * [FIX] Improve the code Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Make SAML to work on Rocket.Chat < 2.3.0 (#1629) * [NEW] Invite links (#1534) * [FIX] Set the http-agent to the form that Rocket.Chat requires for logging (#1482) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] "Following thread" and "Unfollowed Thread" is hardcoded and not translated (#1625) * [FIX] Disable reset button if form didn't changed (#1569) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Header title of RoomInfoView (#1553) * [I18N] Gallery Permissions DE (#1542) * [FIX] Not allow to send messages to archived room (#1623) * [FIX] Profile fields automatically reset (#1502) * [FIX] Show attachment on ThreadMessagesView (#1493) * [NEW] Wordpress auth (#1633) * [CHORE] Add Start Packager script (#1639) * [CHORE] Update RN to 0.61.5 (#1638) * [CHORE] Update RN to 0.61.5 * [CHORE] Update react-native patch Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com> * Bump version to 4.3.1 (#1641) * [FIX] Change force logout rule (#1640) * Bump version to 4.4.0 (#1643) * [IMPROVEMENT] Use MessagingStyle on Android Notification (#1575) * [NEW] Request review (#1627) * [NEW] Pull to refresh RoomView (#1657) * [FIX] Unsubscribe from room (#1655) * [FIX] Server with subdirs (#1646) * [NEW] Clear cache (#1660) * [IMPROVEMENT] Memoize and batch subscriptions updates (#1642) * [FIX] Disallow empty sharing (#1664) * [REGRESSION] Use HTTPS links for sharing and markets protocol for review (#1663) * [FIX] In some cases, share extension doesn't load images (#1649) * [i18n] DE translations for new invite function and some minor fixes (#1631) * [FIX] Remove duplicate jetify step (#1628) minor: also remove 'cd' calls Co-authored-by: Diego Mello <diegolmello@gmail.com> * [REGRESSION] Read messages (#1666) * [i18n] German translations missing (#1670) * [FIX] Notifications crash on older Android Versions (#1672) * [i18n] Added Dutch translation (#1676) * [NEW] Omnichannel Beta (#1674) * [NEW] Confirm logout/clear cache (#1688) * [I18N] Add es-ES language (#1495) * [NEW] UiKit Beta (#1497) * [IMPROVEMENT] Use reselect (#1696) * [FIX] Notification in Android API level less than 24 (#1692) * [IMPROVEMENT] Send tmid on slash commands and media (#1698) * [FIX] Unhandled action on UIKit (#1703) * [NEW] Pull to refresh RoomsList (#1701) * [IMPROVEMENT] Reset app when language is changed (#1702) * [FIX] Small fixes on UIKit (#1709) * [FIX] Spotlight (#1719) * [CHORE] Update react-native-image-crop-picker (#1712) * [FIX] Messages Overlapping (Android) and MessageBox Scroll (iOS) (#1720) * [REGRESSION] Remove @ and # from mention (#1721) * [NEW] Direct message from user info (#1516) * [FIX] Delete slash commands (#1723) * [IMPROVEMENT] Hold URL to copy (#1684) * [FIX] Different sourcemaps generation for Hermes (#1724) * [FIX] Different sourcemaps generation for Hermes * Upload sourcemaps after build * [REVERT] Show emoji keyboard on Android (#1738) * [FIX] Stop logging react-native-image-crop-picker (#1745) * [FIX] Prevent toast ref error (#1744) * [FIX] Prevent reaction map error (#1743) * [FIX] Add missing calls to user info (#1741) * [FIX] Catch room unsubscribe error (#1739) * [i18n] Missing German keys (#1735) * [FIX] Missing i18n on MessagesView title (#1733) * [FIX] UIKit Modal: Weird behavior on Android Tablet (#1742) * [i18n] Missing key on German (#1747) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [i18n] Add Italian (#1736) * [CHORE] Memory leaks investigation (#1675) * [IMPROVEMENT] Alert verify email when enabled (#1725) * [NEW] Jitsi JWT added to URL (#1746) * [FIX] UIKit submit when connection lost (#1748) * Bump version to 4.5.0 (#1761) * [NEW] Default browser (#1752) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] HTTP Basic Auth (#1753) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [IMPROVEMENT] Honor profile fields edit settings (#1687) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [IMPROVEMENT] Room announcements (#1726) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [IMPROVEMENT] Honor Register/Login settings (#1727) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [IMPROVEMENT] Make links clickable on Room Info (#1730) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [NEW] Hide system messages (#1755) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [IMPROVEMENT] Honor "Message_AudioRecorderEnabled" (#1764) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [i18n] Missing de keys (#1765) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Redirect user to SetUsernameView (#1728) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Join Room (#1769) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Accept all media types using * (#1770) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Use RealName when necessary (#1758) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Markdown Line Break (#1783) * [IMPROVEMENT] Remove useMarkdown (#1774) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [IMPROVEMENT] Open browser rather than webview on Create Workspace (#1788) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [IMPROVEMENT] Markdown perf (#1796) * [FIX] Stop video when modal is closed (#1787) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Hide reply notification action when there are missing data (#1771) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [i18n] Added Japanese translation (#1781) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Reset password error message (#1772) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Close tablet modal (#1773) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Setting not present (#1775) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Thread header (#1776) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Keyboard tracking loses input ref (#1784) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [NEW] Mark message as unread (#1785) Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com> * [IMPROVEMENT] Log server version (#1786) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [IMPROVEMENT] Add loading message on long running tasks (#1798) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [CHORE] Switch Apple account on Fastlane (#1810) * [FIX] Watermelon throwing "Cannot update a record with pending updates" (#1754) * [FIX] Detox tests (#1790) * [CHORE] Use markdown preview on RoomView Header (#1807) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] LoginSignup blink services (#1809) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [IMPROVEMENT] Request user presence on demand (#1813) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Remove all invited users when create a channel (#1814) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Pop from room which you have been removed (#1819) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Room Info styles (#1820) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [i18n] Add missing German keys (#1800) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Empty mentions for @all and @here when real name is enabled (#1822) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [TESTS] Markdown added to Storybook (#1812) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [REGRESSION] Room View header title (#1827) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Storybook snapshots (#1831) Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com> * [FIX] Mentions (#1829) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Thread message not found (#1830) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Separate delete and remove channel (#1832) * Rename to delete room * Separate delete and remove channel * handleRemoved -> handleRoomRemoved * [FIX] Navigate to RoomsList & Handle tablet case Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com> * [NEW] Filter system messages per room (#1815) Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com> Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] e2e tests (#1838) * [FIX] Consecutive clear cache calls freezing app (#1851) * Bump version to 4.5.1 (#1853) * [FIX][iOS] Ignore silent mode on audio player (#1862) * [IMPROVEMENT] Create App Group property on Info.plist (#1858) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [IMPROVEMENT] Make username clickable on message (#1618) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Show proper error message on profile (#1768) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [IMPROVEMENT] Show toast when a message is starred/unstarred (#1616) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Incorrect size params to avatar endpoint (#1875) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Remove unrecognized emoji flags on android (#1887) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Remove react-native global installs (#1886) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Emojis transparent on android (#1881) Co-authored-by: Diego Mello <diegolmello@gmail.com> * Bump acorn from 5.7.3 to 5.7.4 (#1876) Bumps [acorn](https://github.com/acornjs/acorn) from 5.7.3 to 5.7.4. - [Release notes](https://github.com/acornjs/acorn/releases) - [Commits](https://github.com/acornjs/acorn/compare/5.7.3...5.7.4) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Diego Mello <diegolmello@gmail.com> * Bump version to 4.6.0 (#1911) * [FIX] Encode Image URI (#1909) * [FIX] Encode Image URI * [FIX] Check if Image is Valid Co-authored-by: Diego Mello <diegolmello@gmail.com> * [NEW] Adaptive Icons (#1904) * Remove unnecessary stuff from debug build * Adaptive icon for experimental app * [FIX] Stop showing message on leave channel (#1896) * [FIX] Leave room don't show 'was removed' message * [FIX] Remove duplicated code Co-authored-by: Diego Mello <diegolmello@gmail.com> * [i18n] Added missing German translations(#1900) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Linkedin OAuth login (#1913) * [CHORE] Fix typo in CreateChannel View (#1930) * [FIX] Respect protocol in HTTP Auth IPs (#1933) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Use new LinkedIn OAuth url (#1935) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [CHORE] Use storyboard on splash screen (#1939) * Update react-native-bootsplash * iOS * Fix android * [FIX] Check if avatar exists before create Icon (#1927) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Ignore self typing event (#1950) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Change default directory listing to Users (#1948) * fix: change default directory listing to Users * follow server settings * Fix state to props Co-authored-by: Diego Mello <diegolmello@gmail.com> * [NEW] Onboarding layout (#1954) * Onboarding texts * OnboardingView * FormContainer * Minor fixes * NewServerView * Remove code * Refactor * WorkspaceView * Stash * Login with email working * Login with * Join open * Revert "Login with" This reverts commit d05dc507d2e9a2db76d433b9b1f62192eba35dbd. * Fix create account styles * Register * Refactor * LoginServices component * Refactor * Multiple servers * Remove native images * Refactor styles * Fix testid * Fix add server on tablet * i18n * Fix close modal * Fix TOTP * [FIX] Registration disabled * [FIX] Login Services separator * Fix logos * Fix AppVersion name * I18n * Minor fixes * [FIX] Custom Fields Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com> * [NEW] Create discussions (#1942) * [WIP][NEW] Create Discussion * [FIX] Clear multiselect & Translations * [NEW] Create Discussion at MessageActions * [NEW] Disabled Multiselect * [FIX] Initial channel * [NEW] Create discussion on MessageBox Actions * [FIX] Crashing on edit name * [IMPROVEMENT] New message layout * [CHORE] Update README * [NEW] Avatars on MultiSelect * [FIX] Select Users * [FIX] Add redirect and Handle tablet * [IMPROVEMENT] Split CreateDiscussionView * [FIX] Create a discussion inner discussion * [FIX] Create a discussion * [I18N] Add pt-br * Change icons * [FIX] Nav to discussion & header title * Fix header Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Load messages (#1910) * Create updateLastOpen param on readMessages * Remove InteractionManager from load messages * [NEW] Custom Status (#1811) * [NEW] Custom Status * [FIX] Subscribe to changes * [FIX] Improve code using Banner component * [IMPROVEMENT] Toggle modal * [NEW] Edit custom status from Sidebar * [FIX] Modal when tablet * [FIX] Styles * [FIX] Switch to react-native-promp-android * [FIX] Custom Status UI * [TESTS] E2E Custom Status * Fix banner * Fix banner * Fix subtitle * status text * Fix topic header * Fix RoomActionsView topic * Fix header alignment on Android * [FIX] RoomInfo crashes when without statusText * [FIX] Use users.setStatus * [FIX] Remove customStatus of ProfileView * [FIX] Room View Thread Header Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] UI issues of Create Discussion View (#1965) * [NEW] Direct Message between multiple users (#1958) * [WIP] DM between multiple users * [WIP][NEW] Create new DM between multiple users * [IMPROVEMENT] Improve createChannel Sagas * [IMPROVEMENT] Selected Users view * [IMPROVEMENT] Room Actions of Group DM * [NEW] Create new DM between multiple users * [NEW] Group DM avatar * [FIX] Directory border * [IMPROVEMENT] Use isGroupChat * [CHORE] Remove legacy getRoomMemberId * [NEW] RoomTypeIcon * [FIX] No use legacy method on RoomInfoView * [FIX] Blink header when create new DM * [FIX] Only show create direct message option when allowed * [FIX] RoomInfoView * pt-BR * Few fixes * Create button name * Show create button only after a user is selected * Fix max users issues Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Add server and hide login (#1968) * Navigate to new server workspace from ServerDropdown if there's no token * Hide login button based on login services and Accounts_ShowFormLogin setting * [FIX] Lint Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com> * [FIX] MultiSelect Keyboard behavior (Android) (#1969) * fixed-modal-position * made-changes Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com> * [FIX] Bottom border style on DirectoryView (#1963) * [FIX] Border style * [FIX] Refactoring * [FIX] fix color of border * Undo Co-authored-by: Aroo <azhaubassar@gmail.com> Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Clear settings on server change (#1967) * [FIX] Deeplinking without RoomId (#1925) * [FIX] Deeplinking without rid * [FIX] Join channel * [FIX] Deep linking without rid * Update app/lib/methods/canOpenRoom.js Co-authored-by: Diego Mello <diegolmello@gmail.com> * [NEW] Two Factor authentication via email (#1961) * First api call working * [NEW] REST API Post wrapper 2FA * [NEW] Send 2FA on Email * [I18n] Add translations * [NEW] Translations & Cancel totp * [CHORE] Totp -> TwoFactor * [NEW] Two Factor by email * [NEW] Tablet Support * [FIX] Text colors * [NEW] Password 2fa * [FIX] Encrypt password on 2FA * [NEW] MethodCall2FA * [FIX] Password fallback * [FIX] Wrap all post/methodCall with 2fa * [FIX] Wrap missed function * few fixes * [FIX] Use new TOTP on Login * [improvement] 2fa methodCall Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com> * [FIX] Correct message for manual approval user Registration (#1906) * [FIX] Correct message for manual approval from admin shown on Registeration * lint fix - added semicolon * Updated the translations * [FIX] Translations * i18n to match server Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com> Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Direct Message between multiple users REST (#1974) * [FIX] Investigate app losing connection issues (#1890) * [WIP] Reopen without timeOut & ping with 5 sec & Fix Unsubscribe * [FIX] Remove duplicated close * [FIX] Use no-dist lib * [FIX] Try minor fix * [FIX] Try reopen connection when app was put on foreground * [FIX] Remove timeout * [FIX] Build * [FIX] Patch * [FIX] Snapshot * [IMPROVEMENT] Decrease time to reopen * [FIX] Some fixes * [FIX] Update sdk version * [FIX] Subscribe Room Once * [CHORE] Update sdk * [FIX] Subscribe Room * [FIX] Try to resend missed subs * [FIX] Users never show status when start app without network * [FIX] Subscribe to room * [FIX] Multiple servers * [CHORE] Update SDK * [FIX] Don't duplicate streams on subscribeAll * [FIX] Server version when start the app offline * [FIX] Server version cached * [CHORE] Remove unnecessary code * [FIX] Offline server version * [FIX] Subscribe before connect * [FIX] Remove unncessary props * [FIX] Update sdk * [FIX] User status & Unsubscribe Typing * [FIX] Typing at incorrect room * [FIX] Multiple Servers * [CHORE] Update SDK * [REVERT] Undo some changes on SDK * [CHORE] Update sdk to prevent incorrect subscribes * [FIX] Prevent no reconnect * [FIX] Remove close on open * [FIX] Clear typing when disconnect/connect to SDK * [CHORE] Update SDK * [CHORE] Update SDK * Update SDK * fix merge develop Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Single message thread inserting thread without rid (#1999) * [FIX] ThreadMessagesView crashing on load (#1997) * [FIX] Saml (#1996) * [FIX] SAML incorrect close * [FIX] Pathname Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Change user own status (#1995) * [FIX] Change user own status * [IMPROVEMENT] Set activeUsers Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Loading all updated rooms after app resume (#1998) * [FIX] Loading all updated rooms after app resume * Fix room date on RoomItem Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Change notifications preferences (#2000) * [FIX] Change notifications preferences * [IMPROVEMENT] Picker View * [I18N] Translations * [FIX] Picker Selection * [FIX] List border * [FIX] Prevent crash * [FIX] Not-Pref tablet * [FIX] Use same style of LanguageView * [IMPROVEMENT] Send listItem title Co-authored-by: Diego Mello <diegolmello@gmail.com> * Bump version to 4.6.1 (#2001) * [FIX] DM header blink (#2011) * [FIX] Split get settings into two requests (#2017) * [FIX] Split get settings into two requests * [FIX] Clear settings only when change server * [IMPROVEMENT] Move the way to clear settings * [REVERT] Revert some changes * [FIX] Server Icon Co-authored-by: Diego Mello <diegolmello@gmail.com> * [REGRESSION] Invite Links (#2007) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Read only channel/broadcast (#1951) * [FIX] Read only channel/broadcast * [FIX] Roles missing * [FIX] Check roles to readOnly * [FIX] Can post * [FIX] Respect post-readonly permission * [FIX] Search a room readOnly Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Cas auth (#2024) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Login TOTP Compatibility to older servers (#2018) * [FIX] Login TOTP Compatibility to older servers * [FIX] Android crashes if use double negation Co-authored-by: Diego Mello <diegolmello@gmail.com> * Bump version to 4.6.4 (#2029) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Lint (#2030) * [FIX] UIKit with only one block (#2022) * [FIX] Message with only one block * [FIX] Update headers Co-authored-by: Diego Mello <diegolmello@gmail.com> * Bump version to 4.7.0 (#2035) * [FIX] Action Tint Color on Black theme (#2081) * [FIX] Prevent crash when thread is not found (#2080) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Prevent double click (#2079) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Show slash commands when disconnected (#2078) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Backhandler onboarding (#2077) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Respect UI_Allow_room_names_with_special_chars setting (#2076) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] RoomsList update sometimes isn't fired (#2071) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [IMPROVEMENT] Stop inserting last message as message object from rooms stream if room is focused (#2069) * [IMPROVEMENT] No insert last message if the room is focused * fix discussion/threads Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Hide system messages (#2067) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Pending update (#2066) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Prevent crash when room.uids was not inserted yet (#2055) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FEATURE] Save video (#2063) * added-feature-save-video * fix sha256 Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com> Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Send totp-code to meteor call (#2050) * fixed-issue * removed-variable-name-errors * reverted-last-commit Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] MessageBox mention shouldn't show group DMs (#2049) * fixed-issue * [FIX] Filter users only if it's not a group chat Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com> Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] AttachmentView (Android)(Tablet) (#2047) * [fix]Tablet attachment View and Room Navigation * fix weird navigation and margin bottom Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com> Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Allow special chars in Filename (#2020) * fixed-filename-issue * improve Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com> Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Recorded audio on Android doesn't play on iOS (#2073) * react-native-video -> expo-av * remove react-native-video * Add audio mode * update mocks * [FIX] Loading bigger than play/pause Co-authored-by: Diego Mello <diegolmello@gmail.com> * [IMPROVEMENT] Message Touchable (#2082) * [FIX] Avatar touchable * [IMPROVEMENT] onLongPress on all Message Touchables * [IMPROVEMENT] User & baseUrl on MessageContext * [FIX] Context Access * [FIX] BaseURL * Fix User Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] ReactionsModal (#2085) * [NEW] Delete Server (#1975) * [NEW] Delete server Co-authored-by: Bruno Dantas <oliveiradantas96@gmail.com> Co-authored-by: Calebe Rios <calebersmendes@gmail.com> * [FIX] Revert removed function Co-authored-by: Bruno Dantas <oliveiradantas96@gmail.com> Co-authored-by: Calebe Rios <calebersmendes@gmail.com> * pods * i18n * Revert "pods" This reverts commit 2854a1650538159aeeafe90fdb2118d12b76a82f. Co-authored-by: Bruno Dantas <oliveiradantas96@gmail.com> Co-authored-by: Calebe Rios <calebersmendes@gmail.com> Co-authored-by: Diego Mello <diegolmello@gmail.com> * [IMPROVEMENT] Change server while connecting/updating (#1981) * [IMPROVEMENT] Change server while connecting * [FIX] Not login/reconnect to previous server * [FIX] Abort all fetch while connecting * [FIX] Abort sdk fetch * [FIX] Patch-package * Add comments Co-authored-by: Diego Mello <diegolmello@gmail.com> * [IMPROVEMENT] Keep screen awake while recording/playing some audio (#2089) * [IMPROVEMENT] Keep screen awake while recording/playing some audio * [FIX] Add expo-keep-awake mock * [FIX] UIKit crashing when UIKitModal receive update event (#2088) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [IMPROVEMENT] Close announcement banner (#2064) * [NEW] Created new field in subscription table Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * [NEW] New field added to obeserver in room view Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * [NEW] Added icon and new design to banner Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * [NEW] Close banner function works Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * [IMPROVEMENT] closed banner status now update correctly Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * improve banner style Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com> Co-authored-by: Diego Mello <diegolmello@gmail.com> * Update all dependencies (#2008) * Android RN 62 * First steps iOS * Second step iOS * iOS compiling * "New" build system * Finish iOS * Flipper * Update to RN 0.62.1 * expo libs * Hermes working * Fix lint * Fix android build * Patches * Dev patches * Patch WatermelonDB: https://github.com/Nozbe/WatermelonDB/pull/660 * Fix jitsi * Update several minors * Update dev minors and lint * react-native-keyboard-input * Few updates * device info * react-native-fast-image * Navigation bar color * react-native-picker-select * webview * reactotron-react-native * Watermelondb * RN 0.62.2 * Few updates * Fix selection * update gems * remove lib * finishing * tests * Use node 10 * Re-enable app bundle * iOS build * Update jitsi ios * [NEW] Passcode and biometric unlock (#2059) * Update expo libs * Configure expo-local-authentication * ScreenLockedView * Authenticate server change * Auth on app resume * localAuthentication util * Add servers.lastLocalAuthenticatedSession column * Save last session date on background * Use our own version of app state redux * Fix libs * Remove inactive * ScreenLockConfigView * Apply on saved data * Auto lock option label * Starting passcode * Basic passcode flow working * Change passcode * Check if biometry is enrolled * Use fork * Migration * Patch expo-local-authentication * Use async storage * Styling * Timer * Refactor * Lock orientation portrait when not on tablet * share extension * Deep linking * Share extension * Refactoring passcode * use state * Stash * Refactor * Change passcode * Animate dots on error * Matching passcodes * Shake * Remove lib * Delete button * Fade animation on modal * Refactoring * ItemInfo * I18n * I18n * Remove unnecessary prop * Save biometry column * Raise time to lock to 30 seconds * Vibrate on wrong confirmation passcode * Reset attempts and save last authentication on local passcode confirmation * Remove inline style * Save last auth * Fix header blink * Change function name * Fix android modal * Fix vibration permission * PasscodeEnter calls biometry * Passcode on the state * Biometry button on PasscodeEnter * Show whole passcode * Secure passcode * Save passcode with promise to prevent empty passcodes and immediately lock * Patch expo-local-authentication * I18n * Fix biometry being called every time * Blur screen on app inactive * Revert "Blur screen on app inactive" This reverts commit a4ce812934adcf6cf87eb1a92aec9283e2f26753. * Remove immediately because of how Activities work on Android * Pods * New layout * stash * Layout refactored * Fix icons * Force set passcode from server * Lint * Improve permission message * Forced passcode subtitle * Disable based on admin's choice * Require local authentication on login success * Refactor * Update tests * Update react-native-device-info to fix notch * Lint * Fix modal * Fix icons * Fix min auto lock time * Review * keep enabled on mobile * fix forced by admin when enable unlock with passcode * use DEFAULT_AUTO_LOCK when manual enable screenLock * fix check has passcode * request biometry on first password * reset auto time lock when disabled on server Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com> * [FIX] Messages View (#2090) * [FIX] Messages View * [FIX] Opening PDF from Files View * [FIX] Audio * [FIX] SearchMessagesView Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Big names overflow (#2072) * [FIX] Big names overflow * [FIX] Message time Co-authored-by: devyaniChoubey <devyanichoubey16@gmail.com> * [FIX] Some alignments * fix user item overflow * some adjustments Co-authored-by: devyaniChoubey <devyanichoubey16@gmail.com> Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Avatar of message as an emoji (#2038) * fixed-issue * removed-hardcoded-emoji * Merge develop * replaced markdown with emoji componenent * made-changes * use avatar onPress Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com> Co-authored-by: Diego Mello <diegolmello@gmail.com> * [NEW] Livechat (#2004) * [WIP][NEW] Livechat info/actions * [IMPROVEMENT] RoomActionsView * [NEW] Visitor Navigation * [NEW] Get Department REST * [FIX] Borders * [IMPROVEMENT] Refactor RoomInfo View * [FIX] Error while navigate from mention -> roomInfo * [NEW] Livechat Fields * [NEW] Close Livechat * [WIP] Forward livechat * [NEW] Return inquiry * [WIP] Comment when close livechat * [WIP] Improve roomInfo * [IMPROVEMENT] Forward room * [FIX] Department picker * [FIX] Picker without results * [FIX] Superfluous argument * [FIX] Check permissions on RoomActionsView * [FIX] Livechat permissions * [WIP] Show edit to livechat * [I18N] Add pt-br translations * [WIP] Livechat Info * [IMPROVEMENT] Livechat info * [WIP] Livechat Edit * [WIP] Livechat edit * [WIP] Livechat Edit * [WIP] Livechat edit scroll * [FIX] Edit customFields * [FIX] Clean livechat customField * [FIX] Visitor Navigation * [NEW] Next input logic LivechatEdit * [FIX] Add livechat data to subscription * [FIX] Revert change * [NEW] Livechat user Status * [WIP] Livechat tags * [NEW] Edit livechat tags * [FIX] Prevent some crashes * [FIX] Forward * [FIX] Return Livechat error * [FIX] Prevent livechat info crash * [IMPROVEMENT] Use input style on forward chat * OnboardingSeparator -> OrSeparator * [FIX] Go to next input * [NEW] Added some icons * [NEW] Livechat close * [NEW] Forward Room Action * [FIX] Livechat edit style * [FIX] Change status logic * [CHORE] Remove unnecessary logic * [CHORE] Remove unnecessary code * [CHORE] Remove unecessary case * [FIX] Superfluous argument * [IMPROVEMENT] Submit livechat edit * [CHORE] Remove textInput type * [FIX] Livechat edit * [FIX] Livechat Edit * [FIX] Use same effect * [IMPROVEMENT] Tags input * [FIX] Add empty tag * Fix minor issues * Fix typo * insert livechat room data to our room object * review * add method calls server version Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Delete Subs (#2091) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Android build (#2094) * [FIX] Blink header DM (#2093) * [FIX] Blink header DM * Remove query * [FIX] Push RoomInfoView * remove unnecessary try/catch * [FIX] RoomInfo > Message (Tablet) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Default biometry enabled (#2095) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [IMPROVEMENT] Enable navigating to a room from auth deep linking (#2115) * Wait for login success to navigate * Enable auth and room deep linking at the same time * [FIX] NewMessageView Press Item should open DM (#2116) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Roles throwing error (#2110) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Wait attach activity before changeNavigationBarColor (#2111) * [FIX] Wait attach activity before changeNavigationBarColor * Remove timeout and add try/catch Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] UIKit crash when some app send a list (#2117) * [FIX] StoryBook * [FIX] UIKit crash when some app send a list * [CHORE] Update snapshot * [CHORE] Remove token & id * [FIX] Change bar color while no activity attached (#2130) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Screen Lock options i18n (#2120) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [i18n] Added missing German translation strings (#2105) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Sometimes SDK is null when try to connect (#2131) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Autocomplete position on Android (#2106) * [FIX] Autocomplete position on Android * [FIX] Set selection to 0 when needed Co-authored-by: Diego Mello <diegolmello@gmail.com> * Revert "[FIX] Autocomplete position on Android (#2106)" (#2136) This reverts commit e8c38d6f6f69ae396a4aae6e37336617da739a6d. * [FIX] Here and all mentions shouldn't refer to users (#2137) * [FIX] No send data to bugsnag if it's an aborted request (#2133) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [TESTS] Update and separate E2E tests (#2126) * Tests passing until roomslist * create room * roominfo * change server * broadcast * profile * custom status * forgot password * working * room and onboarding * Tests separated * config.yml refactor * Revert "config.yml refactor" This reverts commit 0e984d3029e47612726bf199553f7abdf24843e5. * CI * lint * CI refactor * Onboarding tests * npx detox * Add all tests * Save brew cache * mac-env executor * detox-test command * Update readme * Remove folder * [FIX] Screen Lock Time respect local value (#2141) * [FIX] Screen Lock Time respect local value * [FIX] Enable biometry at the first passcode change Co-authored-by: phriedrich <info@phriedrich.de> Co-authored-by: Guilherme Siqueira <guilhersiqueira@gmail.com> Co-authored-by: Prateek Jain <44807945+Prateek93a@users.noreply.github.com> Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com> Co-authored-by: Prateek Jain <prateek93a@gmail.com> Co-authored-by: devyaniChoubey <52153085+devyaniChoubey@users.noreply.github.com> Co-authored-by: Bernard Seow <ssbing99@gmail.com> Co-authored-by: Hiroki Ishiura <ishiura@ja2.so-net.ne.jp> Co-authored-by: Exordian <jakob.englisch@gmail.com> Co-authored-by: Daanchaam <daanhendriks97@gmail.com> Co-authored-by: Youssef Muhamad <emaildeyoussefmuhamad@gmail.com> Co-authored-by: Iván Álvarez <ialvarezpereira@gmail.com> Co-authored-by: Sarthak Pranesh <41206172+sarthakpranesh@users.noreply.github.com> Co-authored-by: Michele Pellegrini <pellettiero@users.noreply.github.com> Co-authored-by: Tanmoy Bhowmik <tanmoy.openroot@gmail.com> Co-authored-by: Hibikine Kage <14365761+hibikine@users.noreply.github.com> Co-authored-by: Ezequiel de Oliveira <ezequiel1de1oliveira@gmail.com> Co-authored-by: Neil Agarwal <neil@neilagarwal.me> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Govind Dixit <GOVINDDIXIT93@GMAIL.COM> Co-authored-by: Zhaubassarova Aruzhan <49000079+azhaubassar@users.noreply.github.com> Co-authored-by: Aroo <azhaubassar@gmail.com> Co-authored-by: Sarthak Pranesh <sarthak.pranesh2018@vitstudent.ac.in> Co-authored-by: Siddharth Padhi <padhisiddharth31@gmail.com> Co-authored-by: Bruno Dantas <oliveiradantas96@gmail.com> Co-authored-by: Calebe Rios <calebersmendes@gmail.com> Co-authored-by: devyaniChoubey <devyanichoubey16@gmail.com>
2020-05-25 20:54:27 +00:00
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <algorithm>
#include <exception>
#include <functional>
#include <memory>
#include <type_traits>
#include <utility>
#include <vector>
#include <folly/Optional.h>
#include <folly/Portability.h>
#include <folly/ScopeGuard.h>
#include <folly/Try.h>
#include <folly/Unit.h>
#include <folly/Utility.h>
#include <folly/executors/DrivableExecutor.h>
#include <folly/executors/TimedDrivableExecutor.h>
#include <folly/functional/Invoke.h>
#include <folly/futures/Portability.h>
#include <folly/futures/Promise.h>
#include <folly/futures/detail/Types.h>
#include <folly/lang/Exception.h>
#if FOLLY_HAS_COROUTINES
#include <folly/experimental/coro/Traits.h>
#include <experimental/coroutine>
#endif
// boring predeclarations and details
#include <folly/futures/Future-pre.h>
namespace folly {
class FOLLY_EXPORT FutureException : public std::logic_error {
public:
using std::logic_error::logic_error;
};
class FOLLY_EXPORT FutureInvalid : public FutureException {
public:
FutureInvalid() : FutureException("Future invalid") {}
};
/// At most one continuation may be attached to any given Future.
///
/// If a continuation is attached to a future to which another continuation has
/// already been attached, then an instance of FutureAlreadyContinued will be
/// thrown instead.
class FOLLY_EXPORT FutureAlreadyContinued : public FutureException {
public:
FutureAlreadyContinued() : FutureException("Future already continued") {}
};
class FOLLY_EXPORT FutureNotReady : public FutureException {
public:
FutureNotReady() : FutureException("Future not ready") {}
};
class FOLLY_EXPORT FutureCancellation : public FutureException {
public:
FutureCancellation() : FutureException("Future was cancelled") {}
};
class FOLLY_EXPORT FutureTimeout : public FutureException {
public:
FutureTimeout() : FutureException("Timed out") {}
};
class FOLLY_EXPORT FuturePredicateDoesNotObtain : public FutureException {
public:
FuturePredicateDoesNotObtain()
: FutureException("Predicate does not obtain") {}
};
class FOLLY_EXPORT FutureNoTimekeeper : public FutureException {
public:
FutureNoTimekeeper() : FutureException("No timekeeper available") {}
};
class FOLLY_EXPORT FutureNoExecutor : public FutureException {
public:
FutureNoExecutor() : FutureException("No executor provided to via") {}
};
template <class T>
class Future;
template <class T>
class SemiFuture;
template <class T>
class FutureSplitter;
#if FOLLY_FUTURE_USING_FIBER
namespace fibers {
class Baton;
}
#endif
namespace futures {
namespace detail {
template <class T>
class FutureBase {
protected:
using Core = futures::detail::Core<T>;
using CoreCallback = typename Core::Callback;
public:
typedef T value_type;
/// Construct from a value (perfect forwarding)
///
/// Postconditions:
///
/// - `valid() == true`
/// - `isReady() == true`
/// - `hasValue() == true`
template <
class T2 = T,
typename = typename std::enable_if<
!isFuture<typename std::decay<T2>::type>::value &&
!isSemiFuture<typename std::decay<T2>::type>::value &&
std::is_constructible<Try<T>, T2>::value>::type>
/* implicit */ FutureBase(T2&& val);
/// Construct a (logical) FutureBase-of-void.
///
/// Postconditions:
///
/// - `valid() == true`
/// - `isReady() == true`
/// - `hasValue() == true`
template <class T2 = T>
/* implicit */ FutureBase(
typename std::enable_if<std::is_same<Unit, T2>::value>::type*);
template <
class... Args,
typename std::enable_if<std::is_constructible<T, Args&&...>::value, int>::
type = 0>
explicit FutureBase(in_place_t, Args&&... args)
: core_(Core::make(in_place, std::forward<Args>(args)...)) {}
FutureBase(FutureBase<T> const&) = delete;
FutureBase(SemiFuture<T>&&) noexcept;
FutureBase(Future<T>&&) noexcept;
// not copyable
FutureBase(Future<T> const&) = delete;
FutureBase(SemiFuture<T> const&) = delete;
~FutureBase();
/// true if this has a shared state;
/// false if this has been either moved-out or created without a shared state.
bool valid() const noexcept {
return core_ != nullptr;
}
/// Returns a reference to the result value if it is ready, with a reference
/// category and const-qualification like those of the future.
///
/// Does not `wait()`; see `get()` for that.
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
/// - `isReady() == true` (else throws FutureNotReady)
///
/// Postconditions:
///
/// - If an exception has been captured (i.e., if `hasException() == true`),
/// throws that exception.
/// - This call does not mutate the future's value.
/// - However calling code may mutate that value (including moving it out by
/// move-constructing or move-assigning another value from it), for
/// example, via the `&` or the `&&` overloads or via casts.
T& value() &;
T const& value() const&;
T&& value() &&;
T const&& value() const&&;
/// Returns a reference to the result's Try if it is ready, with a reference
/// category and const-qualification like those of the future.
///
/// Does not `wait()`; see `get()` for that.
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
/// - `isReady() == true` (else throws FutureNotReady)
///
/// Postconditions:
///
/// - This call does not mutate the future's result.
/// - However calling code may mutate that result (including moving it out by
/// move-constructing or move-assigning another result from it), for
/// example, via the `&` or the `&&` overloads or via casts.
Try<T>& result() &;
Try<T> const& result() const&;
Try<T>&& result() &&;
Try<T> const&& result() const&&;
/// True when the result (or exception) is ready; see value(), result(), etc.
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
bool isReady() const;
/// True if the result is a value (not an exception) on a future for which
/// isReady returns true.
///
/// Equivalent to result().hasValue()
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
/// - `isReady() == true` (else throws FutureNotReady)
bool hasValue() const;
/// True if the result is an exception (not a value) on a future for which
/// isReady returns true.
///
/// Equivalent to result().hasException()
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
/// - `isReady() == true` (else throws FutureNotReady)
bool hasException() const;
/// Returns either an Optional holding the result or an empty Optional
/// depending on whether or not (respectively) the promise has been
/// fulfilled (i.e., `isReady() == true`).
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == true` (note however that this moves-out the result when
/// it returns a populated `Try<T>`, which effects any subsequent use of
/// that result, e.g., `poll()`, `result()`, `value()`, `get()`, etc.)
Optional<Try<T>> poll();
/// This is not the method you're looking for.
///
/// This needs to be public because it's used by make* and when*, and it's
/// not worth listing all those and their fancy template signatures as
/// friends. But it's not for public consumption.
void setCallback_(
CoreCallback&& func,
InlineContinuation = InlineContinuation::forbid);
/// Provides a threadsafe back-channel so the consumer's thread can send an
/// interrupt-object to the producer's thread.
///
/// If the promise-holder registers an interrupt-handler and consumer thread
/// raises an interrupt early enough (details below), the promise-holder
/// will typically halt its work, fulfilling the future with an exception
/// or some special non-exception value.
///
/// However this interrupt request is voluntary, asynchronous, & advisory:
///
/// - Voluntary: the producer will see the interrupt only if the producer uses
/// a `Promise` object and registers an interrupt-handler;
/// see `Promise::setInterruptHandler()`.
/// - Asynchronous: the producer will see the interrupt only if `raise()` is
/// called before (or possibly shortly after) the producer is done producing
/// its result, which is asynchronous with respect to the call to `raise()`.
/// - Advisory: the producer's interrupt-handler can do whatever it wants,
/// including ignore the interrupt or perform some action other than halting
/// its producer-work.
///
/// Guidelines:
///
/// - It is ideal if the promise-holder can both halt its work and fulfill the
/// promise early, typically with the same exception that was delivered to
/// the promise-holder in the form of an interrupt.
/// - If the promise-holder does not do this, and if it holds the promise
/// alive for a long time, then the whole continuation chain will not be
/// invoked and the whole future chain will be kept alive for that long time
/// as well.
/// - It is also ideal if the promise-holder can invalidate the promise.
/// - The promise-holder must also track whether it has set a result in the
/// interrupt handler so that it does not attempt to do so outside the
/// interrupt handler, and must track whether it has set a result in its
/// normal flow so that it does not attempt to do so in the interrupt
/// handler, since setting a result twice is an error. Because the interrupt
/// handler can be invoked in some other thread, this tracking may have to
/// be done with some form of concurrency control.
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - has no visible effect if `raise()` was previously called on `this` or
/// any other Future/SemiFuture that uses the same shared state as `this`.
/// - has no visible effect if the producer never (either in the past or in
/// the future) registers an interrupt-handler.
/// - has no visible effect if the producer fulfills its promise (sets the
/// result) before (or possibly also shortly after) receiving the interrupt.
/// - otherwise the promise-holder's interrupt-handler is called, passing the
/// exception (within an `exception_wrapper`).
///
/// The specific thread used to invoke the producer's interrupt-handler (if
/// it is called at all) depends on timing:
///
/// - if the interrupt-handler is registered prior to `raise()` (or possibly
/// concurrently within the call to `raise()`), the interrupt-handler will
/// be executed using this current thread within the call to `raise()`.
/// - if the interrupt-handler is registered after `raise()` (and possibly
/// concurrently within the call to `raise()`), the interrupt-handler will
/// be executed using the producer's thread within the call to
/// `Promise::setInterruptHandler()`.
///
/// Synchronizes between `raise()` (in the consumer's thread)
/// and `Promise::setInterruptHandler()` (in the producer's thread).
void raise(exception_wrapper interrupt);
/// Raises the specified exception-interrupt.
/// See `raise(exception_wrapper)` for details.
template <class E>
void raise(E&& exception) {
raise(make_exception_wrapper<typename std::remove_reference<E>::type>(
std::forward<E>(exception)));
}
/// Raises a FutureCancellation interrupt.
/// See `raise(exception_wrapper)` for details.
void cancel() {
raise(FutureCancellation());
}
protected:
friend class Promise<T>;
template <class>
friend class SemiFuture;
template <class>
friend class Future;
// Throws FutureInvalid if there is no shared state object; else returns it
// by ref.
//
// Implementation methods should usually use this instead of `this->core_`.
// The latter should be used only when you need the possibly-null pointer.
Core& getCore() {
return getCoreImpl(*this);
}
Core const& getCore() const {
return getCoreImpl(*this);
}
template <typename Self>
static decltype(auto) getCoreImpl(Self& self) {
if (!self.core_) {
throw_exception<FutureInvalid>();
}
return *self.core_;
}
Try<T>& getCoreTryChecked() {
return getCoreTryChecked(*this);
}
Try<T> const& getCoreTryChecked() const {
return getCoreTryChecked(*this);
}
template <typename Self>
static decltype(auto) getCoreTryChecked(Self& self) {
auto& core = self.getCore();
if (!core.hasResult()) {
throw_exception<FutureNotReady>();
}
return core.getTry();
}
// shared core state object
// usually you should use `getCore()` instead of directly accessing `core_`.
Core* core_;
explicit FutureBase(Core* obj) : core_(obj) {}
explicit FutureBase(futures::detail::EmptyConstruct) noexcept;
void detach();
void throwIfInvalid() const;
void throwIfContinued() const;
void assign(FutureBase<T>&& other) noexcept;
Executor* getExecutor() const {
return getCore().getExecutor();
}
DeferredExecutor* getDeferredExecutor() const {
return getCore().getDeferredExecutor();
}
// Sets the Executor within the Core state object of `this`.
// Must be called either before attaching a callback or after the callback
// has already been invoked, but not concurrently with anything which might
// trigger invocation of the callback.
void setExecutor(futures::detail::KeepAliveOrDeferred x) {
getCore().setExecutor(std::move(x));
}
// Variant: returns a value
// e.g. f.thenTry([](Try<T> t){ return t.value(); });
template <typename F, typename R>
typename std::enable_if<!R::ReturnsFuture::value, typename R::Return>::type
thenImplementation(F&& func, R, InlineContinuation);
// Variant: returns a Future
// e.g. f.thenTry([](Try<T> t){ return makeFuture<T>(t); });
template <typename F, typename R>
typename std::enable_if<R::ReturnsFuture::value, typename R::Return>::type
thenImplementation(F&& func, R, InlineContinuation);
};
template <class T>
Future<T> convertFuture(SemiFuture<T>&& sf, const Future<T>& f);
class DeferredExecutor;
template <typename T>
DeferredExecutor* getDeferredExecutor(SemiFuture<T>& future);
template <typename T>
futures::detail::DeferredWrapper stealDeferredExecutor(SemiFuture<T>& future);
} // namespace detail
template <class T>
void detachOn(folly::Executor::KeepAlive<> exec, folly::SemiFuture<T>&& fut);
template <class T>
void detachOnGlobalCPUExecutor(folly::SemiFuture<T>&& fut);
} // namespace futures
/// The interface (along with Future) for the consumer-side of a
/// producer/consumer pair.
///
/// Future vs. SemiFuture:
///
/// - The consumer-side should generally start with a SemiFuture, not a Future.
/// - Example, when a library creates and returns a future, it should usually
/// return a `SemiFuture`, not a Future.
/// - Reason: so the thread policy for continuations (`.thenValue`, etc.) can be
/// specified by the library's caller (using `.via()`).
/// - A SemiFuture is converted to a Future using `.via()`.
/// - Use `makePromiseContract()` when creating both a Promise and an associated
/// SemiFuture/Future.
///
/// When practical, prefer SemiFuture/Future's nonblocking style/pattern:
///
/// - the nonblocking style uses continuations, e.g., `.thenValue`, etc.; the
/// continuations are deferred until the result is available.
/// - the blocking style blocks until complete, e.g., `.wait()`, `.get()`, etc.
/// - the two styles cannot be mixed within the same future; use one or the
/// other.
///
/// SemiFuture/Future also provide a back-channel so an interrupt can
/// be sent from consumer to producer; see SemiFuture/Future's `raise()`
/// and Promise's `setInterruptHandler()`.
///
/// The consumer-side SemiFuture/Future objects should generally be accessed
/// via a single thread. That thread is referred to as the 'consumer thread.'
template <class T>
class SemiFuture : private futures::detail::FutureBase<T> {
private:
using Base = futures::detail::FutureBase<T>;
using DeferredExecutor = futures::detail::DeferredExecutor;
using TimePoint = std::chrono::system_clock::time_point;
public:
~SemiFuture();
/// Creates/returns an invalid SemiFuture, that is, one with no shared state.
///
/// Postcondition:
///
/// - `RESULT.valid() == false`
static SemiFuture<T> makeEmpty();
/// Type of the value that the producer, when successful, produces.
using typename Base::value_type;
/// Construct a SemiFuture from a value (perfect forwarding)
///
/// Postconditions:
///
/// - `valid() == true`
/// - `isReady() == true`
/// - `hasValue() == true`
/// - `hasException() == false`
/// - `value()`, `get()`, `result()` will return the forwarded `T`
template <
class T2 = T,
typename = typename std::enable_if<
!isFuture<typename std::decay<T2>::type>::value &&
!isSemiFuture<typename std::decay<T2>::type>::value &&
std::is_constructible<Try<T>, T2>::value>::type>
/* implicit */ SemiFuture(T2&& val) : Base(std::forward<T2>(val)) {}
/// Construct a (logical) SemiFuture-of-void.
///
/// Postconditions:
///
/// - `valid() == true`
/// - `isReady() == true`
/// - `hasValue() == true`
template <class T2 = T>
/* implicit */ SemiFuture(
typename std::enable_if<std::is_same<Unit, T2>::value>::type* p = nullptr)
: Base(p) {}
/// Construct a SemiFuture from a `T` constructed from `args`
///
/// Postconditions:
///
/// - `valid() == true`
/// - `isReady() == true`
/// - `hasValue() == true`
/// - `hasException() == false`
/// - `value()`, `get()`, `result()` will return the newly constructed `T`
template <
class... Args,
typename std::enable_if<std::is_constructible<T, Args&&...>::value, int>::
type = 0>
explicit SemiFuture(in_place_t, Args&&... args)
: Base(in_place, std::forward<Args>(args)...) {}
SemiFuture(SemiFuture<T> const&) = delete;
// movable
SemiFuture(SemiFuture<T>&&) noexcept;
// safe move-constructabilty from Future
/* implicit */ SemiFuture(Future<T>&&) noexcept;
using Base::cancel;
using Base::hasException;
using Base::hasValue;
using Base::isReady;
using Base::poll;
using Base::raise;
using Base::result;
using Base::setCallback_;
using Base::valid;
using Base::value;
SemiFuture& operator=(SemiFuture const&) = delete;
SemiFuture& operator=(SemiFuture&&) noexcept;
SemiFuture& operator=(Future<T>&&) noexcept;
/// Blocks until the promise is fulfilled, either by value (which is returned)
/// or exception (which is thrown).
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
/// - must not have a continuation, e.g., via `.thenValue()` or similar
///
/// Postconditions:
///
/// - `valid() == false`
T get() &&;
/// Blocks until the semifuture is fulfilled, or until `dur` elapses. Returns
/// the value (moved-out), or throws the exception (which might be a
/// FutureTimeout exception).
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == false`
T get(HighResDuration dur) &&;
/// Blocks until the future is fulfilled. Returns the Try of the result
/// (moved-out).
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == false`
Try<T> getTry() &&;
/// Blocks until the future is fulfilled, or until `dur` elapses.
/// Returns the Try of the result (moved-out), or throws FutureTimeout
/// exception.
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == false`
Try<T> getTry(HighResDuration dur) &&;
/// Blocks the caller's thread until this Future `isReady()`, i.e., until the
/// asynchronous producer has stored a result or exception.
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == true`
/// - `isReady() == true`
/// - `&RESULT == this`
SemiFuture<T>& wait() &;
/// Blocks the caller's thread until this Future `isReady()`, i.e., until the
/// asynchronous producer has stored a result or exception.
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == true` (but the calling code can trivially move-out `*this`
/// by assigning or constructing the result into a distinct object).
/// - `&RESULT == this`
/// - `isReady() == true`
SemiFuture<T>&& wait() &&;
/// Blocks until the future is fulfilled, or `dur` elapses.
/// Returns true if the future was fulfilled.
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == false`
bool wait(HighResDuration dur) &&;
/// Returns a Future which will call back on the other side of executor.
Future<T> via(Executor::KeepAlive<> executor) &&;
Future<T> via(Executor::KeepAlive<> executor, int8_t priority) &&;
/// Defer work to run on the consumer of the future.
/// Function must take a Try as a parameter.
/// This work will be run either on an executor that the caller sets on the
/// SemiFuture, or inline with the call to .get().
///
/// NB: This is a custom method because boost-blocking executors is a
/// special-case for work deferral in folly. With more general boost-blocking
/// support all executors would boost block and we would simply use some form
/// of driveable executor here.
///
/// All forms of defer will run the continuation inline with the execution of
/// the previous callback in the chain if the callback attached to the
/// previous future that triggers execution of func runs on the same executor
/// that func would be executed on.
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == false`
/// - `RESULT.valid() == true`
template <typename F>
SemiFuture<typename futures::detail::tryCallableResult<T, F>::value_type>
defer(F&& func) &&;
/// Defer work to run on the consumer of the future.
/// Function must take a const Executor::KeepAlive<>& and a Try as parameters.
///
/// As for defer(F&& func) except as the first parameter to func a KeepAlive
/// representing the executor running the work will be provided.
template <typename F>
SemiFuture<
typename futures::detail::tryExecutorCallableResult<T, F>::value_type>
deferExTry(F&& func) &&;
/// Defer work to run on the consumer of the future.
/// Function must take a Try as a parameter.
///
/// As for defer(F&& func) but supporting function references.
template <typename R, typename... Args>
auto defer(R (&func)(Args...)) && {
return std::move(*this).defer(&func);
}
/// Defer for functions taking a T rather than a Try<T>.
///
/// All forms of defer will run the continuation inline with the execution of
/// the previous callback in the chain if the callback attached to the
/// previous future that triggers execution of func runs on the same executor
/// that func would be executed on.
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == false`
/// - `RESULT.valid() == true`
template <typename F>
SemiFuture<typename futures::detail::valueCallableResult<T, F>::value_type>
deferValue(F&& func) &&;
/// Defer for functions taking a T rather than a Try<T>.
/// Function must take a const Executor::KeepAlive<>& and a T as parameters.
///
/// As for deferValue(F&& func) except as the first parameter to func a
/// KeepAlive representing the executor running the work will be provided.
template <typename F>
SemiFuture<
typename futures::detail::valueExecutorCallableResult<T, F>::value_type>
deferExValue(F&& func) &&;
/// Defer work to run on the consumer of the future.
/// Function must take a T as a parameter.
///
/// As for deferValue(F&& func) but supporting function references.
template <typename R, typename... Args>
auto deferValue(R (&func)(Args...)) && {
return std::move(*this).deferValue(&func);
}
/// Set an error continuation for this SemiFuture where the continuation can
/// be called with a known exception type and returns a `T`, `Future<T>`, or
/// `SemiFuture<T>`.
///
/// Example:
///
/// ```
/// makeSemiFuture()
/// .defer([] {
/// throw std::runtime_error("oh no!");
/// return 42;
/// })
/// .deferError(folly::tag_t<std::runtime_error>{}, [] (auto const& e) {
/// LOG(INFO) << "std::runtime_error: " << e.what();
/// return -1; // or makeFuture<int>(-1) or makeSemiFuture<int>(-1)
/// });
/// ```
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == false`
/// - `RESULT.valid() == true`
template <class ExceptionType, class F>
SemiFuture<T> deferError(tag_t<ExceptionType>, F&& func) &&;
/// As for deferError(tag_t<ExceptionType>, F&& func) but supporting function
/// references.
template <class ExceptionType, class R, class... Args>
SemiFuture<T> deferError(tag_t<ExceptionType> tag, R (&func)(Args...)) && {
return std::move(*this).deferError(tag, &func);
}
/// As for deferError(tag_t<ExceptionType>, F&& func) but makes the exception
/// explicit as a template argument rather than using a tag type.
template <class ExceptionType, class F>
SemiFuture<T> deferError(F&& func) && {
return std::move(*this).deferError(
tag_t<ExceptionType>{}, std::forward<F>(func));
}
/// Set an error continuation for this SemiFuture where the continuation can
/// be called with `exception_wrapper&&` and returns a `T`, `Future<T>`, or
/// `SemiFuture<T>`.
///
/// Example:
///
/// makeSemiFuture()
/// .defer([] {
/// throw std::runtime_error("oh no!");
/// return 42;
/// })
/// .deferError([] (exception_wrapper&& e) {
/// LOG(INFO) << e.what();
/// return -1; // or makeFuture<int>(-1) or makeSemiFuture<int>(-1)
/// });
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == false`
/// - `RESULT.valid() == true`
template <class F>
SemiFuture<T> deferError(F&& func) &&;
/// As for deferError(tag_t<ExceptionType>, F&& func) but supporting function
/// references.
template <class R, class... Args>
SemiFuture<T> deferError(R (&func)(Args...)) && {
return std::move(*this).deferError(&func);
}
/// Convenience method for ignoring the value and creating a Future<Unit>.
/// Exceptions still propagate.
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - Calling code should act as if `valid() == false`,
/// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true`
SemiFuture<Unit> unit() &&;
/// If this SemiFuture completes within duration dur from now, propagate its
/// value. Otherwise satisfy the returned SemiFuture with a FutureTimeout
/// exception.
///
/// The optional Timekeeper is as with futures::sleep().
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - Calling code should act as if `valid() == false`,
/// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true`
SemiFuture<T> within(HighResDuration dur, Timekeeper* tk = nullptr) && {
return std::move(*this).within(dur, FutureTimeout(), tk);
}
/// If this SemiFuture completes within duration dur from now, propagate its
/// value. Otherwise satisfy the returned SemiFuture with exception e.
///
/// The optional Timekeeper is as with futures::sleep().
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - Calling code should act as if `valid() == false`,
/// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true`
template <class E>
SemiFuture<T> within(HighResDuration dur, E e, Timekeeper* tk = nullptr) &&;
/// Delay the completion of this SemiFuture for at least this duration from
/// now. The optional Timekeeper is as with futures::sleep().
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == false`
/// - `RESULT.valid() == true`
SemiFuture<T> delayed(HighResDuration dur, Timekeeper* tk = nullptr) &&;
/// Returns a future that completes inline, as if the future had no executor.
/// Intended for porting legacy code without behavioral change, and for rare
/// cases where this is really the intended behavior.
/// Future is unsafe in the sense that the executor it completes on is
/// non-deterministic in the standard case.
/// For new code, or to update code that temporarily uses this, please
/// use via and pass a meaningful executor.
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == false`
/// - `RESULT.valid() == true`
Future<T> toUnsafeFuture() &&;
#if FOLLY_HAS_COROUTINES
// Customise the co_viaIfAsync() operator so that SemiFuture<T> can be
// directly awaited within a folly::coro::Task coroutine.
friend Future<T> co_viaIfAsync(
folly::Executor::KeepAlive<> executor,
SemiFuture<T>&& future) noexcept {
return std::move(future).via(std::move(executor));
}
#endif
private:
friend class Promise<T>;
template <class>
friend class futures::detail::FutureBase;
template <class>
friend class SemiFuture;
template <class>
friend class Future;
friend futures::detail::DeferredWrapper
futures::detail::stealDeferredExecutor<T>(SemiFuture<T>&);
friend DeferredExecutor* futures::detail::getDeferredExecutor<T>(
SemiFuture<T>&);
using Base::setExecutor;
using Base::throwIfInvalid;
using typename Base::Core;
template <class T2>
friend SemiFuture<T2> makeSemiFuture(Try<T2>);
explicit SemiFuture(Core* obj) : Base(obj) {}
explicit SemiFuture(futures::detail::EmptyConstruct) noexcept
: Base(futures::detail::EmptyConstruct{}) {}
// Throws FutureInvalid if !this->core_
futures::detail::DeferredWrapper stealDeferredExecutor();
/// Blocks until the future is fulfilled, or `dur` elapses.
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == true`
/// - `&RESULT == this`
/// - `isReady()` will be indeterminate - may or may not be true
SemiFuture<T>& wait(HighResDuration dur) &;
static void releaseDeferredExecutor(Core* core);
};
template <class T>
std::pair<Promise<T>, SemiFuture<T>> makePromiseContract() {
auto p = Promise<T>();
auto f = p.getSemiFuture();
return std::make_pair(std::move(p), std::move(f));
}
/// The interface (along with SemiFuture) for the consumer-side of a
/// producer/consumer pair.
///
/// Future vs. SemiFuture:
///
/// - The consumer-side should generally start with a SemiFuture, not a Future.
/// - Example, when a library creates and returns a future, it should usually
/// return a `SemiFuture`, not a Future.
/// - Reason: so the thread policy for continuations (`.thenValue`, etc.) can be
/// specified by the library's caller (using `.via()`).
/// - A SemiFuture is converted to a Future using `.via()`.
/// - Use `makePromiseContract()` when creating both a Promise and an associated
/// SemiFuture/Future.
///
/// When practical, prefer SemiFuture/Future's nonblocking style/pattern:
///
/// - the nonblocking style uses continuations, e.g., `.thenValue`, etc.; the
/// continuations are deferred until the result is available.
/// - the blocking style blocks until complete, e.g., `.wait()`, `.get()`, etc.
/// - the two styles cannot be mixed within the same future; use one or the
/// other.
///
/// SemiFuture/Future also provide a back-channel so an interrupt can
/// be sent from consumer to producer; see SemiFuture/Future's `raise()`
/// and Promise's `setInterruptHandler()`.
///
/// The consumer-side SemiFuture/Future objects should generally be accessed
/// via a single thread. That thread is referred to as the 'consumer thread.'
template <class T>
class Future : private futures::detail::FutureBase<T> {
private:
using Base = futures::detail::FutureBase<T>;
public:
/// Type of the value that the producer, when successful, produces.
using typename Base::value_type;
/// Construct a Future from a value (perfect forwarding)
///
/// Postconditions:
///
/// - `valid() == true`
/// - `isReady() == true`
/// - `hasValue() == true`
/// - `value()`, `get()`, `result()` will return the forwarded `T`
template <
class T2 = T,
typename = typename std::enable_if<
!isFuture<typename std::decay<T2>::type>::value &&
!isSemiFuture<typename std::decay<T2>::type>::value &&
std::is_constructible<Try<T>, T2>::value>::type>
/* implicit */ Future(T2&& val) : Base(std::forward<T2>(val)) {}
/// Construct a (logical) Future-of-void.
///
/// Postconditions:
///
/// - `valid() == true`
/// - `isReady() == true`
/// - `hasValue() == true`
template <class T2 = T>
/* implicit */ Future(
typename std::enable_if<std::is_same<Unit, T2>::value>::type* p = nullptr)
: Base(p) {}
/// Construct a Future from a `T` constructed from `args`
///
/// Postconditions:
///
/// - `valid() == true`
/// - `isReady() == true`
/// - `hasValue() == true`
/// - `hasException() == false`
/// - `value()`, `get()`, `result()` will return the newly constructed `T`
template <
class... Args,
typename std::enable_if<std::is_constructible<T, Args&&...>::value, int>::
type = 0>
explicit Future(in_place_t, Args&&... args)
: Base(in_place, std::forward<Args>(args)...) {}
Future(Future<T> const&) = delete;
// movable
Future(Future<T>&&) noexcept;
// converting move
template <
class T2,
typename std::enable_if<
!std::is_same<T, typename std::decay<T2>::type>::value &&
std::is_constructible<T, T2&&>::value &&
std::is_convertible<T2&&, T>::value,
int>::type = 0>
/* implicit */ Future(Future<T2>&& other)
: Future(std::move(other).thenValue(
[](T2&& v) { return T(std::move(v)); })) {}
template <
class T2,
typename std::enable_if<
!std::is_same<T, typename std::decay<T2>::type>::value &&
std::is_constructible<T, T2&&>::value &&
!std::is_convertible<T2&&, T>::value,
int>::type = 0>
explicit Future(Future<T2>&& other)
: Future(std::move(other).thenValue(
[](T2&& v) { return T(std::move(v)); })) {}
template <
class T2,
typename std::enable_if<
!std::is_same<T, typename std::decay<T2>::type>::value &&
std::is_constructible<T, T2&&>::value,
int>::type = 0>
Future& operator=(Future<T2>&& other) {
return operator=(
std::move(other).thenValue([](T2&& v) { return T(std::move(v)); }));
}
using Base::cancel;
using Base::hasException;
using Base::hasValue;
using Base::isReady;
using Base::poll;
using Base::raise;
using Base::result;
using Base::setCallback_;
using Base::valid;
using Base::value;
/// Creates/returns an invalid Future, that is, one with no shared state.
///
/// Postcondition:
///
/// - `RESULT.valid() == false`
static Future<T> makeEmpty();
// not copyable
Future& operator=(Future const&) = delete;
// movable
Future& operator=(Future&&) noexcept;
/// Call e->drive() repeatedly until the future is fulfilled.
///
/// Examples of DrivableExecutor include EventBase and ManualExecutor.
///
/// Returns the fulfilled value (moved-out) or throws the fulfilled exception.
T getVia(DrivableExecutor* e);
/// Call e->drive() repeatedly until the future is fulfilled, or `dur`
/// elapses.
///
/// Returns the fulfilled value (moved-out), throws the fulfilled exception,
/// or on timeout throws FutureTimeout.
T getVia(TimedDrivableExecutor* e, HighResDuration dur);
/// Call e->drive() repeatedly until the future is fulfilled. Examples
/// of DrivableExecutor include EventBase and ManualExecutor. Returns a
/// reference to the Try of the value.
Try<T>& getTryVia(DrivableExecutor* e);
/// getTryVia but will wait only until `dur` elapses. Returns the
/// Try of the value (moved-out) or may throw a FutureTimeout exception.
Try<T>& getTryVia(TimedDrivableExecutor* e, HighResDuration dur);
/// Unwraps the case of a Future<Future<T>> instance, and returns a simple
/// Future<T> instance.
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - Calling code should act as if `valid() == false`,
/// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true`
template <class F = T>
typename std::
enable_if<isFuture<F>::value, Future<typename isFuture<T>::Inner>>::type
unwrap() &&;
/// Returns a Future which will call back on the other side of executor.
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == false`
/// - `RESULT.valid() == true`
Future<T> via(Executor::KeepAlive<> executor) &&;
Future<T> via(Executor::KeepAlive<> executor, int8_t priority) &&;
/// Returns a Future which will call back on the other side of executor.
///
/// When practical, use the rvalue-qualified overload instead - it's faster.
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == true`
/// - `RESULT.valid() == true`
/// - when `this` gets fulfilled, it automatically fulfills RESULT
Future<T> via(Executor::KeepAlive<> executor) &;
Future<T> via(Executor::KeepAlive<> executor, int8_t priority) &;
/// When this Future has completed, execute func which is a function that
/// can be called with either `T&&` or `Try<T>&&`.
///
/// Func shall return either another Future or a value.
///
/// thenInline will run the continuation inline with the execution of the
/// previous callback in the chain if the callback attached to the previous
/// future that triggers execution of func runs on the same executor that func
/// would be executed on.
///
/// A Future for the return type of func is returned.
///
/// Versions of these functions with Inline in the name will run the
/// continuation inline if the executor the previous task completes on matches
/// the executor the next is to be enqueued on to.
///
/// Future<string> f2 = f1.thenTry([](Try<T>&&) { return string("foo"); });
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - Calling code should act as if `valid() == false`,
/// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true`
template <typename F>
Future<typename futures::detail::tryCallableResult<T, F>::value_type> then(
F&& func) && {
return std::move(*this).thenTry(std::forward<F>(func));
}
template <typename F>
Future<typename futures::detail::tryCallableResult<T, F>::value_type>
thenInline(F&& func) && {
return std::move(*this).thenTryInline(std::forward<F>(func));
}
/// Variant where func is an member function
///
/// struct Worker { R doWork(Try<T>); }
///
/// Worker *w;
/// Future<R> f2 = f1.thenTry(&Worker::doWork, w);
///
/// This is just sugar for
///
/// f1.thenTry(std::bind(&Worker::doWork, w));
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - Calling code should act as if `valid() == false`,
/// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true`
template <typename R, typename Caller, typename... Args>
Future<typename isFuture<R>::Inner> then(
R (Caller::*func)(Args...),
Caller* instance) &&;
/// Execute the callback via the given Executor. The executor doesn't stick.
///
/// Contrast
///
/// f.via(x).then(b).then(c)
///
/// with
///
/// f.then(x, b).then(c)
///
/// In the former both b and c execute via x. In the latter, only b executes
/// via x, and c executes via the same executor (if any) that f had.
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - Calling code should act as if `valid() == false`,
/// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true`
template <class Arg>
auto then(Executor::KeepAlive<> x, Arg&& arg) && = delete;
/// When this Future has completed, execute func which is a function that
/// can be called with `Try<T>&&` (often a lambda with parameter type
/// `auto&&` or `auto`).
///
/// Func shall return either another Future or a value.
///
/// Versions of these functions with Inline in the name will run the
/// continuation inline with the execution of the previous callback in the
/// chain if the callback attached to the previous future that triggers
/// execution of func runs on the same executor that func would be executed
/// on.
///
/// A Future for the return type of func is returned.
///
/// Future<string> f2 = std::move(f1).thenTry([](auto&& t) {
/// ...
/// return string("foo");
/// });
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == false`
/// - `RESULT.valid() == true`
template <typename F>
Future<typename futures::detail::tryCallableResult<T, F>::value_type> thenTry(
F&& func) &&;
template <typename F>
Future<typename futures::detail::tryCallableResult<T, F>::value_type>
thenTryInline(F&& func) &&;
template <typename F>
Future<typename futures::detail::tryExecutorCallableResult<T, F>::value_type>
thenExTry(F&& func) &&;
template <typename F>
Future<typename futures::detail::tryExecutorCallableResult<T, F>::value_type>
thenExTryInline(F&& func) &&;
template <typename R, typename... Args>
auto thenTry(R (&func)(Args...)) && {
return std::move(*this).thenTry(&func);
}
template <typename R, typename... Args>
auto thenTryInline(R (&func)(Args...)) && {
return std::move(*this).thenTryInline(&func);
}
/// When this Future has completed, execute func which is a function that
/// can be called with `T&&` (often a lambda with parameter type
/// `auto&&` or `auto`).
///
/// Func shall return either another Future or a value.
///
/// Versions of these functions with Inline in the name will run the
/// continuation inline with the execution of the previous callback in the
/// chain if the callback attached to the previous future that triggers
/// execution of func runs on the same executor that func would be executed
/// on.
///
/// A Future for the return type of func is returned.
///
/// Future<string> f2 = f1.thenValue([](auto&& v) {
/// ...
/// return string("foo");
/// });
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == false`
/// - `RESULT.valid() == true`
template <typename F>
Future<typename futures::detail::valueCallableResult<T, F>::value_type>
thenValue(F&& func) &&;
template <typename F>
Future<typename futures::detail::valueCallableResult<T, F>::value_type>
thenValueInline(F&& func) &&;
template <typename F>
Future<
typename futures::detail::valueExecutorCallableResult<T, F>::value_type>
thenExValue(F&& func) &&;
template <typename F>
Future<
typename futures::detail::valueExecutorCallableResult<T, F>::value_type>
thenExValueInline(F&& func) &&;
template <typename R, typename... Args>
auto thenValue(R (&func)(Args...)) && {
return std::move(*this).thenValue(&func);
}
template <typename R, typename... Args>
auto thenValueInline(R (&func)(Args...)) && {
return std::move(*this).thenValueInline(&func);
}
/// Set an error continuation for this Future where the continuation can
/// be called with a known exception type and returns a `T`, `Future<T>`, or
/// `SemiFuture<T>`.
///
/// Example:
///
/// makeFuture()
/// .thenTry([] {
/// throw std::runtime_error("oh no!");
/// return 42;
/// })
/// .thenError(folly::tag_t<std::runtime_error>{}, [] (auto const& e) {
/// LOG(INFO) << "std::runtime_error: " << e.what();
/// return -1; // or makeFuture<int>(-1) or makeSemiFuture<int>(-1)
/// });
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == false`
/// - `RESULT.valid() == true`
template <class ExceptionType, class F>
typename std::enable_if<
isFutureOrSemiFuture<invoke_result_t<F, ExceptionType>>::value,
Future<T>>::type
thenError(tag_t<ExceptionType>, F&& func) &&;
template <class ExceptionType, class F>
typename std::enable_if<
!isFutureOrSemiFuture<invoke_result_t<F, ExceptionType>>::value,
Future<T>>::type
thenError(tag_t<ExceptionType>, F&& func) &&;
template <class ExceptionType, class R, class... Args>
Future<T> thenError(tag_t<ExceptionType> tag, R (&func)(Args...)) && {
return std::move(*this).thenError(tag, &func);
}
template <class ExceptionType, class F>
Future<T> thenError(F&& func) && {
return std::move(*this).thenError(
tag_t<ExceptionType>{}, std::forward<F>(func));
}
/// Set an error continuation for this Future where the continuation can
/// be called with `exception_wrapper&&` and returns a `T`, `Future<T>`, or
/// `SemiFuture<T>`.
///
/// Example:
///
/// makeFuture()
/// .thenTry([] {
/// throw std::runtime_error("oh no!");
/// return 42;
/// })
/// .thenError([] (exception_wrapper&& e) {
/// LOG(INFO) << e.what();
/// return -1; // or makeFuture<int>(-1) or makeSemiFuture<int>(-1)
/// });
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == false`
/// - `RESULT.valid() == true`
template <class F>
typename std::enable_if<
isFutureOrSemiFuture<invoke_result_t<F, exception_wrapper>>::value,
Future<T>>::type
thenError(F&& func) &&;
template <class F>
typename std::enable_if<
!isFutureOrSemiFuture<invoke_result_t<F, exception_wrapper>>::value,
Future<T>>::type
thenError(F&& func) &&;
template <class R, class... Args>
Future<T> thenError(R (&func)(Args...)) && {
return std::move(*this).thenError(&func);
}
/// Convenience method for ignoring the value and creating a Future<Unit>.
/// Exceptions still propagate.
/// This function is identical to .unit().
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - Calling code should act as if `valid() == false`,
/// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true`
Future<Unit> then() &&;
/// Convenience method for ignoring the value and creating a Future<Unit>.
/// Exceptions still propagate.
/// This function is identical to parameterless .then().
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - Calling code should act as if `valid() == false`,
/// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true`
Future<Unit> unit() && {
return std::move(*this).then();
}
/// Set an error continuation for this Future. The continuation should take an
/// argument of the type that you want to catch, and should return a value of
/// the same type as this Future, or a Future of that type (see overload
/// below).
///
/// Example:
///
/// makeFuture()
/// .thenValue([] {
/// throw std::runtime_error("oh no!");
/// return 42;
/// })
/// .thenError<std::runtime_error>([] (std::runtime_error& e) {
/// LOG(INFO) << "std::runtime_error: " << e.what();
/// return -1; // or makeFuture<int>(-1)
/// });
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - Calling code should act as if `valid() == false`,
/// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true`
template <class F>
[[deprecated(
"onError loses the attached executor and is weakly typed. Please move to thenError instead.")]]
typename std::enable_if<
!is_invocable_v<F, exception_wrapper> &&
!futures::detail::Extract<F>::ReturnsFuture::value,
Future<T>>::type
onError(F&& func) && = delete;
/// Overload of onError where the error continuation returns a Future<T>
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - Calling code should act as if `valid() == false`,
/// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true`
template <class F>
[[deprecated(
"onError loses the attached executor and is weakly typed. Please move to thenError instead.")]]
typename std::enable_if<
!is_invocable_v<F, exception_wrapper> &&
futures::detail::Extract<F>::ReturnsFuture::value,
Future<T>>::type
onError(F&& func) && = delete;
/// Overload of onError that takes exception_wrapper and returns Future<T>
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - Calling code should act as if `valid() == false`,
/// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true`
template <class F>
[[deprecated(
"onError loses the attached executor and is weakly typed. Please move to thenError instead.")]]
typename std::enable_if<
is_invocable_v<F, exception_wrapper> &&
futures::detail::Extract<F>::ReturnsFuture::value,
Future<T>>::type
onError(F&& func) && = delete;
/// Overload of onError that takes exception_wrapper and returns T
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - Calling code should act as if `valid() == false`,
/// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true`
template <class F>
[[deprecated(
"onError loses the attached executor and is weakly typed. Please move to thenError instead.")]]
typename std::enable_if<
is_invocable_v<F, exception_wrapper> &&
!futures::detail::Extract<F>::ReturnsFuture::value,
Future<T>>::type
onError(F&& func) && = delete;
template <class R, class... Args>
Future<T> onError(R (&func)(Args...)) && = delete;
// clang-format off
template <class F>
[[deprecated(
"onError loses the attached executor and is weakly typed. Please move to thenError instead.")]]
Future<T> onError(F&& func) & = delete;
/// func is like std::function<void()> and is executed unconditionally, and
/// the value/exception is passed through to the resulting Future.
/// func shouldn't throw, but if it does it will be captured and propagated,
/// and discard any value/exception that this Future has obtained.
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - Calling code should act as if `valid() == false`,
/// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true`
template <class F>
Future<T> ensure(F&& func) &&;
// clang-format on
/// Like thenError, but for timeouts. example:
///
/// Future<int> f = makeFuture<int>(42)
/// .delayed(long_time)
/// .onTimeout(short_time,
/// [] { return -1; });
///
/// or perhaps
///
/// Future<int> f = makeFuture<int>(42)
/// .delayed(long_time)
/// .onTimeout(short_time,
/// [] { return makeFuture<int>(some_exception); });
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - Calling code should act as if `valid() == false`,
/// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true`
template <class F>
Future<T> onTimeout(HighResDuration, F&& func, Timekeeper* = nullptr) &&;
/// If this Future completes within duration dur from now, propagate its
/// value. Otherwise satisfy the returned SemiFuture with a FutureTimeout
/// exception.
///
/// The optional Timekeeper is as with futures::sleep().
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - Calling code should act as if `valid() == false`,
/// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true`
Future<T> within(HighResDuration dur, Timekeeper* tk = nullptr) &&;
/// If this SemiFuture completes within duration dur from now, propagate its
/// value. Otherwise satisfy the returned SemiFuture with exception e.
///
/// The optional Timekeeper is as with futures::sleep().
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - Calling code should act as if `valid() == false`,
/// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true`
template <class E>
Future<T>
within(HighResDuration dur, E exception, Timekeeper* tk = nullptr) &&;
/// Delay the completion of this Future for at least this duration from
/// now. The optional Timekeeper is as with futures::sleep().
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == false`
/// - `RESULT.valid() == true`
Future<T> delayed(HighResDuration, Timekeeper* = nullptr) &&;
/// Blocks until the future is fulfilled. Returns the value (moved-out), or
/// throws the exception. The future must not already have a continuation.
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == false`
T get() &&;
/// Blocks until the future is fulfilled, or until `dur` elapses. Returns the
/// value (moved-out), or throws the exception (which might be a FutureTimeout
/// exception).
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == false`
T get(HighResDuration dur) &&;
/// A reference to the Try of the value
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
/// - `isReady() == true` (else throws FutureNotReady)
Try<T>& getTry();
/// Blocks until this Future is complete.
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == true`
/// - `&RESULT == this`
/// - `isReady() == true`
Future<T>& wait() &;
/// Blocks until this Future is complete.
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == true` (but the calling code can trivially move-out `*this`
/// by assigning or constructing the result into a distinct object).
/// - `&RESULT == this`
/// - `isReady() == true`
Future<T>&& wait() &&;
/// Blocks until this Future is complete, or `dur` elapses.
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == true` (so you may call `wait(...)` repeatedly)
/// - `&RESULT == this`
/// - `isReady()` will be indeterminate - may or may not be true
Future<T>& wait(HighResDuration dur) &;
/// Blocks until this Future is complete or until `dur` passes.
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == true` (but the calling code can trivially move-out `*this`
/// by assigning or constructing the result into a distinct object).
/// - `&RESULT == this`
/// - `isReady()` will be indeterminate - may or may not be true
Future<T>&& wait(HighResDuration dur) &&;
/// Call e->drive() repeatedly until the future is fulfilled. Examples
/// of DrivableExecutor include EventBase and ManualExecutor. Returns a
/// reference to this Future so that you can chain calls if desired.
/// value (moved-out), or throws the exception.
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == true` (does not move-out `*this`)
/// - `&RESULT == this`
Future<T>& waitVia(DrivableExecutor* e) &;
/// Overload of waitVia() for rvalue Futures
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == true` (but the calling code can trivially move-out `*this`
/// by assigning or constructing the result into a distinct object).
/// - `&RESULT == this`
Future<T>&& waitVia(DrivableExecutor* e) &&;
/// As waitVia but may return early after dur passes.
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == true` (does not move-out `*this`)
/// - `&RESULT == this`
Future<T>& waitVia(TimedDrivableExecutor* e, HighResDuration dur) &;
/// Overload of waitVia() for rvalue Futures
/// As waitVia but may return early after dur passes.
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == true` (but the calling code can trivially move-out `*this`
/// by assigning or constructing the result into a distinct object).
/// - `&RESULT == this`
Future<T>&& waitVia(TimedDrivableExecutor* e, HighResDuration dur) &&;
/// If the value in this Future is equal to the given Future, when they have
/// both completed, the value of the resulting Future<bool> will be true. It
/// will be false otherwise (including when one or both Futures have an
/// exception)
Future<bool> willEqual(Future<T>&);
/// predicate behaves like std::function<bool(T const&)>
/// If the predicate does not obtain with the value, the result
/// is a folly::FuturePredicateDoesNotObtain exception
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - Calling code should act as if `valid() == false`,
/// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true`
template <class F>
Future<T> filter(F&& predicate) &&;
/// Like reduce, but works on a Future<std::vector<T / Try<T>>>, for example
/// the result of collect or collectAll
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - Calling code should act as if `valid() == false`,
/// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true`
template <class I, class F>
Future<I> reduce(I&& initial, F&& func) &&;
/// Moves-out `*this`, creating/returning a corresponding SemiFuture.
/// Result will behave like `*this` except result won't have an Executor.
///
/// Postconditions:
///
/// - `RESULT.valid() ==` the original value of `this->valid()`
/// - RESULT will not have an Executor regardless of whether `*this` had one
SemiFuture<T> semi() && {
return SemiFuture<T>{std::move(*this)};
}
#if FOLLY_HAS_COROUTINES
// Overload needed to customise behaviour of awaiting a Future<T>
// inside a folly::coro::Task coroutine.
friend Future<T> co_viaIfAsync(
folly::Executor::KeepAlive<> executor,
Future<T>&& future) noexcept {
return std::move(future).via(std::move(executor));
}
#endif
protected:
friend class Promise<T>;
template <class>
friend class futures::detail::FutureBase;
template <class>
friend class Future;
template <class>
friend class SemiFuture;
template <class>
friend class FutureSplitter;
using Base::setExecutor;
using Base::throwIfContinued;
using Base::throwIfInvalid;
using typename Base::Core;
explicit Future(Core* obj) : Base(obj) {}
explicit Future(futures::detail::EmptyConstruct) noexcept
: Base(futures::detail::EmptyConstruct{}) {}
template <class T2>
friend Future<T2> makeFuture(Try<T2>);
template <class FT>
friend Future<FT> futures::detail::convertFuture(
SemiFuture<FT>&& sf,
const Future<FT>& f);
using Base::detach;
template <class T2>
friend void futures::detachOn(
folly::Executor::KeepAlive<> exec,
folly::SemiFuture<T2>&& fut);
};
/// A Timekeeper handles the details of keeping time and fulfilling delay
/// promises. The returned Future<Unit> will either complete after the
/// elapsed time, or in the event of some kind of exceptional error may hold
/// an exception. These Futures respond to cancellation. If you use a lot of
/// Delays and many of them ultimately are unneeded (as would be the case for
/// Delays that are used to trigger timeouts of async operations), then you
/// can and should cancel them to reclaim resources.
///
/// Users will typically get one of these via Future::sleep(HighResDuration dur)
/// or use them implicitly behind the scenes by passing a timeout to some Future
/// operation.
///
/// Although we don't formally alias Delay = Future<Unit>,
/// that's an appropriate term for it. People will probably also call these
/// Timeouts, and that's ok I guess, but that term is so overloaded I thought
/// it made sense to introduce a cleaner term.
///
/// Remember that HighResDuration is a std::chrono duration (millisecond
/// resolution at the time of writing). When writing code that uses specific
/// durations, prefer using the explicit std::chrono type, e.g.
/// std::chrono::milliseconds over HighResDuration. This makes the code more
/// legible and means you won't be unpleasantly surprised if we redefine
/// HighResDuration to microseconds, or something.
///
/// timekeeper.after(std::chrono::duration_cast<HighResDuration>(someNanoseconds))
class Timekeeper {
public:
virtual ~Timekeeper() = default;
/// Returns a future that will complete after the given duration with the
/// elapsed time. Exceptional errors can happen but they must be
/// exceptional. Use the steady (monotonic) clock.
///
/// The consumer thread may cancel this Future to reclaim resources.
virtual SemiFuture<Unit> after(HighResDuration dur) = 0;
/// Unsafe version of after that returns an inline Future.
/// Any work added to this future will run inline on the Timekeeper's thread.
/// This can potentially cause problems with timing.
///
/// Please migrate to use after + a call to via with a valid, non-inline
/// executor.
Future<Unit> afterUnsafe(HighResDuration dur) {
return after(dur).toUnsafeFuture();
}
/// Returns a future that will complete at the requested time.
///
/// You may cancel this SemiFuture to reclaim resources.
///
/// NB This is sugar for `after(when - now)`, so while you are welcome to
/// use a std::chrono::system_clock::time_point it will not track changes to
/// the system clock but rather execute that many milliseconds in the future
/// according to the steady clock.
template <class Clock>
SemiFuture<Unit> at(std::chrono::time_point<Clock> when);
/// Unsafe version of at that returns an inline Future.
/// Any work added to this future will run inline on the Timekeeper's thread.
/// This can potentially cause problems with timing.
///
/// Please migrate to use at + a call to via with a valid, non-inline
/// executor.
template <class Clock>
Future<Unit> atUnsafe(std::chrono::time_point<Clock> when) {
return at(when).toUnsafeFuture();
}
};
template <class T>
std::pair<Promise<T>, Future<T>> makePromiseContract(Executor::KeepAlive<> e) {
auto p = Promise<T>();
auto f = p.getSemiFuture().via(std::move(e));
return std::make_pair(std::move(p), std::move(f));
}
template <class F>
auto makeAsyncTask(folly::Executor::KeepAlive<> ka, F&& func) {
return
[func = std::forward<F>(func), ka = std::move(ka)](auto&& param) mutable {
return via(
ka,
[func = std::move(func),
param = std::forward<decltype(param)>(param)]() mutable {
return func(std::forward<decltype(param)>(param));
});
};
}
/// This namespace is for utility functions that would usually be static
/// members of Future, except they don't make sense there because they don't
/// depend on the template type (rather, on the type of their arguments in
/// some cases). This is the least-bad naming scheme we could think of. Some
/// of the functions herein have really-likely-to-collide names, like "map"
/// and "sleep".
namespace futures {
/// Returns a Future that will complete after the specified duration. The
/// HighResDuration typedef of a `std::chrono` duration type indicates the
/// resolution you can expect to be meaningful (milliseconds at the time of
/// writing). Normally you wouldn't need to specify a Timekeeper, we will
/// use the global futures timekeeper (we run a thread whose job it is to
/// keep time for futures timeouts) but we provide the option for power
/// users.
///
/// The Timekeeper thread will be lazily created the first time it is
/// needed. If your program never uses any timeouts or other time-based
/// Futures you will pay no Timekeeper thread overhead.
SemiFuture<Unit> sleep(HighResDuration, Timekeeper* = nullptr);
[[deprecated(
"futures::sleep now returns a SemiFuture<Unit>. "
"sleepUnsafe is deprecated. "
"Please call futures::sleep and apply an executor with .via")]] Future<Unit>
sleepUnsafe(HighResDuration, Timekeeper* = nullptr);
/**
* Set func as the callback for each input Future and return a vector of
* Futures containing the results in the input order.
*/
template <
class It,
class F,
class ItT = typename std::iterator_traits<It>::value_type,
class Tag = std::enable_if_t<is_invocable_v<F, typename ItT::value_type&&>>,
class Result = typename decltype(
std::declval<ItT>().thenValue(std::declval<F>()))::value_type>
std::vector<Future<Result>> mapValue(It first, It last, F func);
/**
* Set func as the callback for each input Future and return a vector of
* Futures containing the results in the input order.
*/
template <
class It,
class F,
class ItT = typename std::iterator_traits<It>::value_type,
class Tag =
std::enable_if_t<!is_invocable_v<F, typename ItT::value_type&&>>,
class Result = typename decltype(
std::declval<ItT>().thenTry(std::declval<F>()))::value_type>
std::vector<Future<Result>> mapTry(It first, It last, F func, int = 0);
/**
* Set func as the callback for each input Future and return a vector of
* Futures containing the results in the input order and completing on
* exec.
*/
template <
class It,
class F,
class ItT = typename std::iterator_traits<It>::value_type,
class Tag = std::enable_if_t<is_invocable_v<F, typename ItT::value_type&&>>,
class Result =
typename decltype(std::move(std::declval<ItT>())
.via(std::declval<Executor*>())
.thenValue(std::declval<F>()))::value_type>
std::vector<Future<Result>> mapValue(Executor& exec, It first, It last, F func);
/**
* Set func as the callback for each input Future and return a vector of
* Futures containing the results in the input order and completing on
* exec.
*/
template <
class It,
class F,
class ItT = typename std::iterator_traits<It>::value_type,
class Tag =
std::enable_if_t<!is_invocable_v<F, typename ItT::value_type&&>>,
class Result =
typename decltype(std::move(std::declval<ItT>())
.via(std::declval<Executor*>())
.thenTry(std::declval<F>()))::value_type>
std::vector<Future<Result>>
mapTry(Executor& exec, It first, It last, F func, int = 0);
// Sugar for the most common case
template <class Collection, class F>
auto mapValue(Collection&& c, F&& func)
-> decltype(mapValue(c.begin(), c.end(), func)) {
return mapValue(c.begin(), c.end(), std::forward<F>(func));
}
template <class Collection, class F>
auto mapTry(Collection&& c, F&& func)
-> decltype(mapTry(c.begin(), c.end(), func)) {
return mapTry(c.begin(), c.end(), std::forward<F>(func));
}
// Sugar for the most common case
template <class Collection, class F>
auto mapValue(Executor& exec, Collection&& c, F&& func)
-> decltype(mapValue(exec, c.begin(), c.end(), func)) {
return mapValue(exec, c.begin(), c.end(), std::forward<F>(func));
}
template <class Collection, class F>
auto mapTry(Executor& exec, Collection&& c, F&& func)
-> decltype(mapTry(exec, c.begin(), c.end(), func)) {
return mapTry(exec, c.begin(), c.end(), std::forward<F>(func));
}
/// Carry out the computation contained in the given future if
/// the predicate holds.
///
/// thunk behaves like std::function<Future<T2>(void)> or
/// std::function<SemiFuture<T2>(void)>
template <class F>
auto when(bool p, F&& thunk)
-> decltype(std::declval<invoke_result_t<F>>().unit());
#if FOLLY_FUTURE_USING_FIBER
SemiFuture<Unit> wait(std::unique_ptr<fibers::Baton> baton);
SemiFuture<Unit> wait(std::shared_ptr<fibers::Baton> baton);
#endif
/**
* Returns a lazy SemiFuture constructed by f, which also ensures that ensure is
* called before completion.
* f doesn't get called until the SemiFuture is activated (e.g. through a .get()
* or .via() call). If f gets called, ensure is guaranteed to be called as well.
*/
template <typename F, class Ensure>
auto ensure(F&& f, Ensure&& ensure);
} // namespace futures
/**
Make a completed SemiFuture by moving in a value. e.g.
string foo = "foo";
auto f = makeSemiFuture(std::move(foo));
or
auto f = makeSemiFuture<string>("foo");
*/
template <class T>
SemiFuture<typename std::decay<T>::type> makeSemiFuture(T&& t);
/** Make a completed void SemiFuture. */
SemiFuture<Unit> makeSemiFuture();
/**
Make a SemiFuture by executing a function.
If the function returns a value of type T, makeSemiFutureWith
returns a completed SemiFuture<T>, capturing the value returned
by the function.
If the function returns a SemiFuture<T> already, makeSemiFutureWith
returns just that.
Either way, if the function throws, a failed Future is
returned that captures the exception.
*/
// makeSemiFutureWith(SemiFuture<T>()) -> SemiFuture<T>
template <class F>
typename std::enable_if<
isFutureOrSemiFuture<invoke_result_t<F>>::value,
SemiFuture<typename invoke_result_t<F>::value_type>>::type
makeSemiFutureWith(F&& func);
// makeSemiFutureWith(T()) -> SemiFuture<T>
// makeSemiFutureWith(void()) -> SemiFuture<Unit>
template <class F>
typename std::enable_if<
!(isFutureOrSemiFuture<invoke_result_t<F>>::value),
SemiFuture<lift_unit_t<invoke_result_t<F>>>>::type
makeSemiFutureWith(F&& func);
/// Make a failed Future from an exception_ptr.
/// Because the Future's type cannot be inferred you have to specify it, e.g.
///
/// auto f = makeSemiFuture<string>(std::current_exception());
template <class T>
[[deprecated("use makeSemiFuture(exception_wrapper)")]] SemiFuture<T>
makeSemiFuture(std::exception_ptr const& e);
/// Make a failed SemiFuture from an exception_wrapper.
template <class T>
SemiFuture<T> makeSemiFuture(exception_wrapper ew);
/** Make a SemiFuture from an exception type E that can be passed to
std::make_exception_ptr(). */
template <class T, class E>
typename std::
enable_if<std::is_base_of<std::exception, E>::value, SemiFuture<T>>::type
makeSemiFuture(E const& e);
/** Make a Future out of a Try */
template <class T>
SemiFuture<T> makeSemiFuture(Try<T> t);
/**
Make a completed Future by moving in a value. e.g.
string foo = "foo";
auto f = makeFuture(std::move(foo));
or
auto f = makeFuture<string>("foo");
NOTE: This function is deprecated. Please use makeSemiFuture and pass the
appropriate executor to .via on the returned SemiFuture to get a
valid Future where necessary.
*/
template <class T>
Future<typename std::decay<T>::type> makeFuture(T&& t);
/**
Make a completed void Future.
NOTE: This function is deprecated. Please use makeSemiFuture and pass the
appropriate executor to .via on the returned SemiFuture to get a
valid Future where necessary.
*/
Future<Unit> makeFuture();
/**
Make a Future by executing a function.
If the function returns a value of type T, makeFutureWith
returns a completed Future<T>, capturing the value returned
by the function.
If the function returns a Future<T> already, makeFutureWith
returns just that.
Either way, if the function throws, a failed Future is
returned that captures the exception.
Calling makeFutureWith(func) is equivalent to calling
makeFuture().then(func).
NOTE: This function is deprecated. Please use makeSemiFutureWith and pass the
appropriate executor to .via on the returned SemiFuture to get a
valid Future where necessary.
*/
// makeFutureWith(Future<T>()) -> Future<T>
template <class F>
typename std::
enable_if<isFuture<invoke_result_t<F>>::value, invoke_result_t<F>>::type
makeFutureWith(F&& func);
// makeFutureWith(T()) -> Future<T>
// makeFutureWith(void()) -> Future<Unit>
template <class F>
typename std::enable_if<
!(isFuture<invoke_result_t<F>>::value),
Future<lift_unit_t<invoke_result_t<F>>>>::type
makeFutureWith(F&& func);
/// Make a failed Future from an exception_ptr.
/// Because the Future's type cannot be inferred you have to specify it, e.g.
///
/// auto f = makeFuture<string>(std::current_exception());
template <class T>
[[deprecated("use makeSemiFuture(exception_wrapper)")]] Future<T> makeFuture(
std::exception_ptr const& e);
/// Make a failed Future from an exception_wrapper.
/// NOTE: This function is deprecated. Please use makeSemiFuture and pass the
/// appropriate executor to .via on the returned SemiFuture to get a
/// valid Future where necessary.
template <class T>
Future<T> makeFuture(exception_wrapper ew);
/** Make a Future from an exception type E that can be passed to
std::make_exception_ptr().
NOTE: This function is deprecated. Please use makeSemiFuture and pass the
appropriate executor to .via on the returned SemiFuture to get a
valid Future where necessary.
*/
template <class T, class E>
typename std::enable_if<std::is_base_of<std::exception, E>::value, Future<T>>::
type
makeFuture(E const& e);
/**
Make a Future out of a Try
NOTE: This function is deprecated. Please use makeSemiFuture and pass the
appropriate executor to .via on the returned SemiFuture to get a
valid Future where necessary.
*/
template <class T>
Future<T> makeFuture(Try<T> t);
/*
* Return a new Future that will call back on the given Executor.
* This is just syntactic sugar for makeFuture().via(executor)
*
* @param executor the Executor to call back on
* @param priority optionally, the priority to add with. Defaults to 0 which
* represents medium priority.
*
* @returns a void Future that will call back on the given executor
*/
inline Future<Unit> via(Executor::KeepAlive<> executor);
inline Future<Unit> via(Executor::KeepAlive<> executor, int8_t priority);
/// Execute a function via the given executor and return a future.
/// This is semantically equivalent to via(executor).then(func), but
/// easier to read and slightly more efficient.
template <class Func>
auto via(Executor::KeepAlive<>, Func&& func) -> Future<
typename isFutureOrSemiFuture<decltype(std::declval<Func>()())>::Inner>;
/** When all the input Futures complete, the returned Future will complete.
Errors do not cause early termination; this Future will always succeed
after all its Futures have finished (whether successfully or with an
error).
The Futures are moved in, so your copies are invalid. If you need to
chain further from these Futures, use the variant with an output iterator.
This function is thread-safe for Futures running on different threads. But
if you are doing anything non-trivial after, you will probably want to
follow with `via(executor)` because it will complete in whichever thread the
last Future completes in.
The return type for Future<T> input is a SemiFuture<std::vector<Try<T>>>
for collectX and collectXSemiFuture.
collectXUnsafe returns an inline Future that erases the executor from the
incoming Futures/SemiFutures. collectXUnsafe should be phased out and
replaced with collectX(...).via(e) where e is a valid non-inline executor.
*/
template <class InputIterator>
SemiFuture<std::vector<
Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>
collectAllSemiFuture(InputIterator first, InputIterator last);
/// Sugar for the most common case
template <class Collection>
auto collectAllSemiFuture(Collection&& c)
-> decltype(collectAllSemiFuture(c.begin(), c.end())) {
return collectAllSemiFuture(c.begin(), c.end());
}
// Unsafe variant, see above comment for details
template <class InputIterator>
Future<std::vector<
Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>
collectAllUnsafe(InputIterator first, InputIterator last);
// Unsafe variant sugar, see above comment for details
template <class Collection>
auto collectAllUnsafe(Collection&& c)
-> decltype(collectAllUnsafe(c.begin(), c.end())) {
return collectAllUnsafe(c.begin(), c.end());
}
template <class InputIterator>
SemiFuture<std::vector<
Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>
collectAll(InputIterator first, InputIterator last);
template <class Collection>
auto collectAll(Collection&& c) -> decltype(collectAll(c.begin(), c.end())) {
return collectAll(c.begin(), c.end());
}
/// This version takes a varying number of Futures instead of an iterator.
/// The return type for (Future<T1>, Future<T2>, ...) input
/// is a SemiFuture<std::tuple<Try<T1>, Try<T2>, ...>>.
/// The Futures are moved in, so your copies are invalid.
template <typename... Fs>
SemiFuture<std::tuple<Try<typename remove_cvref_t<Fs>::value_type>...>>
collectAllSemiFuture(Fs&&... fs);
// Unsafe variant of collectAll, see coment above for details. Returns
// a Future<std::tuple<Try<T1>, Try<T2>, ...>> on the Inline executor.
template <typename... Fs>
Future<std::tuple<Try<typename remove_cvref_t<Fs>::value_type>...>>
collectAllUnsafe(Fs&&... fs);
template <typename... Fs>
SemiFuture<std::tuple<Try<typename remove_cvref_t<Fs>::value_type>...>>
collectAll(Fs&&... fs);
/// Like collectAll, but will short circuit on the first exception. Thus, the
/// type of the returned SemiFuture is std::vector<T> instead of
/// std::vector<Try<T>>
template <class InputIterator>
SemiFuture<std::vector<
typename std::iterator_traits<InputIterator>::value_type::value_type>>
collect(InputIterator first, InputIterator last);
/// Sugar for the most common case
template <class Collection>
auto collect(Collection&& c) -> decltype(collect(c.begin(), c.end())) {
return collect(c.begin(), c.end());
}
// Unsafe variant of collect. Returns a Future<std::vector<T>> that
// completes inline.
template <class InputIterator>
Future<std::vector<
typename std::iterator_traits<InputIterator>::value_type::value_type>>
collectUnsafe(InputIterator first, InputIterator last);
/// Sugar for the most common unsafe case. Returns a Future<std::vector<T>>
// that completes inline.
template <class Collection>
auto collectUnsafe(Collection&& c)
-> decltype(collectUnsafe(c.begin(), c.end())) {
return collectUnsafe(c.begin(), c.end());
}
/// Like collectAll, but will short circuit on the first exception. Thus, the
/// type of the returned SemiFuture is std::tuple<T1, T2, ...> instead of
/// std::tuple<Try<T1>, Try<T2>, ...>
template <typename... Fs>
SemiFuture<std::tuple<typename remove_cvref_t<Fs>::value_type...>> collect(
Fs&&... fs);
/** The result is a pair of the index of the first Future to complete and
the Try. If multiple Futures complete at the same time (or are already
complete when passed in), the "winner" is chosen non-deterministically.
This function is thread-safe for Futures running on different threads.
*/
template <class InputIterator>
SemiFuture<std::pair<
size_t,
Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>
collectAny(InputIterator first, InputIterator last);
// Unsafe variant of collectAny, Returns a Future that completes inline.
template <class InputIterator>
Future<std::pair<
size_t,
Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>
collectAnyUnsafe(InputIterator first, InputIterator last);
template <class InputIterator>
SemiFuture<std::pair<
size_t,
Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>
collectAnySemiFuture(InputIterator first, InputIterator last);
/// Sugar for the most common case
template <class Collection>
auto collectAny(Collection&& c) -> decltype(collectAny(c.begin(), c.end())) {
return collectAny(c.begin(), c.end());
}
// Unsafe variant of common form of collectAny, Returns a Future that completes
// inline.
template <class Collection>
auto collectAnyUnsafe(Collection&& c)
-> decltype(collectAnyUnsafe(c.begin(), c.end())) {
return collectAnyUnsafe(c.begin(), c.end());
}
template <class Collection>
auto collectAnySemiFuture(Collection&& c)
-> decltype(collectAnySemiFuture(c.begin(), c.end())) {
return collectAnySemiFuture(c.begin(), c.end());
}
/** Similar to collectAny, collectAnyWithoutException return the first Future to
* complete without exceptions. If none of the future complete without
* exceptions, the last exception will be returned as a result.
*/
template <class InputIterator>
SemiFuture<std::pair<
size_t,
typename std::iterator_traits<InputIterator>::value_type::value_type>>
collectAnyWithoutException(InputIterator first, InputIterator last);
/// Sugar for the most common case
template <class Collection>
auto collectAnyWithoutException(Collection&& c)
-> decltype(collectAnyWithoutException(c.begin(), c.end())) {
return collectAnyWithoutException(c.begin(), c.end());
}
/** when n Futures have completed, the Future completes with a vector of
the index and Try of those n Futures (the indices refer to the original
order, but the result vector will be in an arbitrary order)
Not thread safe.
*/
template <class InputIterator>
SemiFuture<std::vector<std::pair<
size_t,
Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>>
collectN(InputIterator first, InputIterator last, size_t n);
/// Sugar for the most common case
template <class Collection>
auto collectN(Collection&& c, size_t n)
-> decltype(collectN(c.begin(), c.end(), n)) {
return collectN(c.begin(), c.end(), n);
}
/** window creates up to n Futures using the values
in the collection, and then another Future for each Future
that completes
this is basically a sliding window of Futures of size n
func must return a Future for each value in input
*/
template <
class Collection,
class F,
class ItT = typename std::iterator_traits<
typename Collection::iterator>::value_type,
class Result = typename invoke_result_t<F, ItT&&>::value_type>
std::vector<Future<Result>> window(Collection input, F func, size_t n);
template <
class Collection,
class F,
class ItT = typename std::iterator_traits<
typename Collection::iterator>::value_type,
class Result = typename invoke_result_t<F, ItT&&>::value_type>
std::vector<Future<Result>>
window(Executor::KeepAlive<> executor, Collection input, F func, size_t n);
template <typename F, typename T, typename ItT>
using MaybeTryArg = typename std::
conditional<is_invocable_v<F, T&&, Try<ItT>&&>, Try<ItT>, ItT>::type;
/** repeatedly calls func on every result, e.g.
reduce(reduce(reduce(T initial, result of first), result of second), ...)
The type of the final result is a Future of the type of the initial value.
Func can either return a T, or a Future<T>
func is called in order of the input, see unorderedReduce if that is not
a requirement
*/
template <class It, class T, class F>
Future<T> reduce(It first, It last, T&& initial, F&& func);
/// Sugar for the most common case
template <class Collection, class T, class F>
auto reduce(Collection&& c, T&& initial, F&& func) -> decltype(folly::reduce(
c.begin(),
c.end(),
std::forward<T>(initial),
std::forward<F>(func))) {
return folly::reduce(
c.begin(), c.end(), std::forward<T>(initial), std::forward<F>(func));
}
/** like reduce, but calls func on finished futures as they complete
does NOT keep the order of the input
*/
template <class It, class T, class F>
Future<T> unorderedReduce(It first, It last, T initial, F func);
/// Sugar for the most common case
template <class Collection, class T, class F>
auto unorderedReduce(Collection&& c, T&& initial, F&& func)
-> decltype(folly::unorderedReduce(
c.begin(),
c.end(),
std::forward<T>(initial),
std::forward<F>(func))) {
return folly::unorderedReduce(
c.begin(), c.end(), std::forward<T>(initial), std::forward<F>(func));
}
/// Carry out the computation contained in the given future if
/// while the predicate continues to hold.
///
/// if thunk behaves like std::function<Future<T2>(void)>
/// returns Future<Unit>
/// if thunk behaves like std::function<SemiFuture<T2>(void)>
/// returns SemiFuture<Unit>
/// predicate behaves like std::function<bool(void)>
template <class P, class F>
typename std::enable_if<isFuture<invoke_result_t<F>>::value, Future<Unit>>::type
whileDo(P&& predicate, F&& thunk);
template <class P, class F>
typename std::
enable_if<isSemiFuture<invoke_result_t<F>>::value, SemiFuture<Unit>>::type
whileDo(P&& predicate, F&& thunk);
/// Repeat the given future (i.e., the computation it contains) n times.
///
/// thunk behaves like
/// std::function<Future<T2>(void)>
/// or
/// std::function<SemiFuture<T2>(void)>
template <class F>
auto times(int n, F&& thunk);
} // namespace folly
#if FOLLY_HAS_COROUTINES
namespace folly {
namespace detail {
template <typename T>
class FutureAwaitable {
public:
explicit FutureAwaitable(folly::Future<T>&& future) noexcept
: future_(std::move(future)) {}
bool await_ready() {
if (future_.isReady()) {
result_ = std::move(future_.getTry());
return true;
}
return false;
}
T await_resume() {
return std::move(result_).value();
}
Try<T> await_resume_try() {
return std::move(result_);
}
FOLLY_CORO_AWAIT_SUSPEND_NONTRIVIAL_ATTRIBUTES void await_suspend(
std::experimental::coroutine_handle<> h) {
// FutureAwaitable may get destroyed as soon as the callback is executed.
// Make sure the future object doesn't get destroyed until setCallback_
// returns.
auto future = std::move(future_);
future.setCallback_(
[this, h](Executor::KeepAlive<>&&, Try<T>&& result) mutable {
result_ = std::move(result);
h.resume();
});
}
private:
folly::Future<T> future_;
folly::Try<T> result_;
};
} // namespace detail
template <typename T>
inline detail::FutureAwaitable<T>
/* implicit */ operator co_await(Future<T>&& future) noexcept {
return detail::FutureAwaitable<T>(std::move(future));
}
} // namespace folly
#endif
#include <folly/futures/Future-inl.h>