Created
June 25, 2019 15:28
-
-
Save dnevera/240b554a6f304c31ce9ebbeaf91b63ff to your computer and use it in GitHub Desktop.
Promise implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Created by denn nevera on 2019-06-24. | |
// | |
// | |
// source: https://github.com/LifeWanted/liblw/tree/master/source/lw/event | |
// | |
#pragma once | |
#include <atomic> | |
#include <functional> | |
#include <memory> | |
#include <type_traits> | |
#include "capy/amqp_exception.h" | |
namespace capy::event { | |
CAPY_DEFINE_EXCEPTION(PromiseError); | |
// ---------------------------------------------------------------------------------------------- // | |
template<typename T> | |
class Future; | |
// ---------------------------------------------------------------------------------------------- // | |
/// @brief Determines if the given variable is a `Future`, or derives publicly from `Future`. | |
/// | |
/// @tparam T The type to check. | |
template<typename T> | |
struct IsFuture : public std::integral_constant<bool, false> {}; | |
template<typename T> | |
struct IsFuture<Future<T>> : public std::integral_constant<bool, true> {}; | |
template<template<typename> class T, typename Value> | |
struct IsFuture<T<Value>> : | |
public std::integral_constant<bool, std::is_base_of<Future<Value>, T<Value>>::value> | |
{}; | |
// ---------------------------------------------------------------------------------------------- // | |
/// @brief Breaks down a type to the highest non-future layer. | |
/// | |
/// @tparam T The type to break down. | |
template<typename T> | |
struct UnwrapFuture { | |
typedef T result_type; ///< The type that will be promised. | |
typedef Future<T> type; ///< The type of a future for this type. | |
}; | |
template<typename T> | |
struct UnwrapFuture<Future<T>> : public UnwrapFuture<T> {}; | |
// ---------------------------------------------------------------------------------------------- // | |
/// @brief Determines the result of a function as a future. | |
template<typename T> | |
struct FutureResultOf; | |
template<typename F, typename... Args> | |
struct FutureResultOf<F(Args...)> : | |
public UnwrapFuture<typename std::result_of<F(Args...)>::type> | |
{}; | |
// ---------------------------------------------------------------------------------------------- // | |
/// @brief `Promise`s and `Future`s allow for chaining callbacks without nesting. | |
/// | |
/// A `Promise` is the active side of the pair. Asynchronous functions create a promise and later | |
/// fulfill it by either resolving or rejecting the promise. | |
template<typename T = void> | |
class Promise { | |
public: | |
/// @brief Default construction. | |
Promise(void): | |
m_state(new _SharedState()) | |
{ | |
m_state->resolved = false; | |
m_state->rejected = false; | |
m_state->resolve = nullptr; | |
m_state->reject = nullptr; | |
} | |
// ------------------------------------------------------------------------------------------ // | |
/// @brief No copying! | |
Promise(const Promise&) = delete; | |
// ------------------------------------------------------------------------------------------ // | |
/// @brief Moves the promise from `other` to `this`. | |
Promise(Promise&& other): | |
m_state(std::move(other.m_state)) | |
{ | |
other.m_state = nullptr; | |
} | |
// ------------------------------------------------------------------------------------------ // | |
/// @brief Returns a future associated with this promise. | |
Future<T> future(void); | |
// ------------------------------------------------------------------------------------------ // | |
/// @brief Resolves the promise as a success. | |
void resolve(T&& value){ | |
m_state->resolved = true; | |
if (m_state->resolve) { | |
m_state->resolve( std::move( value ) ); | |
} | |
} | |
// ------------------------------------------------------------------------------------------ // | |
/// @copydoc Promise::resolve(T&&) | |
void resolve(const T& value){ | |
resolve(T(value)); | |
} | |
// ------------------------------------------------------------------------------------------ // | |
/// @brief Rejects the promise as a failure. | |
void reject(const error::Exception& err){ | |
m_state->rejected = true; | |
if (m_state->reject) { | |
m_state->reject(err); | |
} | |
else { | |
throw err; | |
} | |
} | |
// ------------------------------------------------------------------------------------------ // | |
/// @brief Resets the promise's internal state so that it can be reused. | |
/// | |
/// @throws PromiseError If the promise is in an unfinished state. | |
void reset(void){ | |
if (!is_finished()) { | |
throw PromiseError(1, "Cannot reset an unfinished promise."); | |
} | |
m_state->resolved = false; | |
m_state->rejected = false; | |
m_state->resolve = nullptr; | |
m_state->reject = nullptr; | |
} | |
// ------------------------------------------------------------------------------------------ // | |
/// @brief Indicates if the promise has been resolved. | |
bool is_resolved(void) const { | |
return m_state->resolved; | |
} | |
// ------------------------------------------------------------------------------------------ // | |
/// @brief Indicates if the promise has been rejected. | |
bool is_rejected(void) const { | |
return m_state->rejected; | |
} | |
// ------------------------------------------------------------------------------------------ // | |
/// @brief Indicates if the promise has been either resolved or rejected. | |
bool is_finished(void) const { | |
return is_resolved() || is_rejected(); | |
} | |
// ------------------------------------------------------------------------------------------ // | |
/// @brief No copying! | |
Promise& operator=(const Promise&) = delete; | |
// ------------------------------------------------------------------------------------------ // | |
/// @brief Moves the promise from `other` into `this`. | |
Promise& operator=(Promise&& other){ | |
m_state = std::move(other.m_state); | |
other.m_state = nullptr; | |
return *this; | |
} | |
private: | |
template<typename Type> | |
friend class ::capy::event::Future; | |
// ------------------------------------------------------------------------------------------ // | |
/// @brief The container for the shared state between promises and futures. | |
struct _SharedState { | |
std::atomic_bool resolved; | |
std::atomic_bool rejected; | |
std::function<void(T&&)> resolve; | |
std::function<void(const error::Exception&)> reject; | |
}; | |
typedef std::shared_ptr<_SharedState> _SharedStatePtr; | |
// ------------------------------------------------------------------------------------------ // | |
/// @brief The state of the promise. | |
_SharedStatePtr m_state; | |
}; | |
// ---------------------------------------------------------------------------------------------- // | |
/// @brief The passive half of the `Promise`-`Future` pair. | |
/// | |
/// `Future`s are the requester's handle on an asynchronous event. They allow callbacks to be | |
/// registered for after it has been started. | |
template<typename T = void> | |
class Future { | |
public: | |
/// @brief The type promised by this future. | |
typedef T result_type; | |
/// @brief The type of Promise that made this future. | |
typedef Promise<T> promise_type; | |
// ------------------------------------------------------------------------------------------ // | |
template<typename Func> | |
auto then(Func&& func){ | |
return then(std::forward<Func>(func), nullptr); | |
} | |
// ------------------------------------------------------------------------------------------ // | |
template<typename Result, typename Func> | |
auto then(Func&& func){ | |
return then<Result>(std::forward<Func>(func), nullptr); | |
} | |
// ------------------------------------------------------------------------------------------ // | |
template<typename Resolve, typename Reject> | |
auto then(Resolve&& resolve, Reject&& reject){ | |
return _then(std::forward<Resolve>(resolve), std::forward<Reject>(reject)); | |
} | |
// ------------------------------------------------------------------------------------------ // | |
template<typename Result, typename Resolve, typename Reject> | |
auto then(Resolve&& resolve, Reject&& reject){ | |
return _then<Result>(std::forward<Resolve>(resolve), std::forward<Reject>(reject)); | |
} | |
// ------------------------------------------------------------------------------------------ // | |
/// @brief Connects this promise to the one provided. | |
/// | |
/// @param promise The promise to resolve/reject with this one. | |
void then(promise_type&& promise); | |
// ------------------------------------------------------------------------------------------ // | |
private: | |
template<typename Type> | |
friend class ::capy::event::Promise; | |
// ------------------------------------------------------------------------------------------ // | |
/// @brief Only `Promise`s can construct us. | |
/// | |
/// @param state The shared state to associate with. | |
Future(const typename promise_type::_SharedStatePtr& state): | |
m_state(state) | |
{} | |
// ------------------------------------------------------------------------------------------ // | |
/// @brief Chaining for generic functors. | |
/// | |
/// @tparam Result The type given functor promises. | |
/// @tparam Resolve A functor type that can take a `Promise&&` as its parameter. | |
/// | |
/// @param resolve The functor to call when this one is resolved. | |
/// | |
/// @return A new future, for when the provided `resolve` completes its action. | |
template< | |
typename Result, | |
typename Resolve, | |
typename Reject, | |
typename = typename std::result_of<Resolve(T&&,Promise<Result>&&)>::type | |
> | |
Future<Result> _then(Resolve&& resolve, Reject&& reject); | |
// ------------------------------------------------------------------------------------------ // | |
/// @brief Chaining for generic functors promising nothing. | |
/// | |
/// @tparam Resolve A functor type that can take a `Promise&&` as its parameter. | |
/// | |
/// @param resolve The functor to call when this one is resolved. | |
/// | |
/// @return A new future, for when the provided `resolve` completes its action. | |
template< | |
typename Resolve, | |
typename Reject, | |
typename = typename std::result_of<Resolve(T&&, Promise<>&&)>::type | |
> | |
Future<> _then(Resolve&& resolve, Reject&& reject); | |
// ------------------------------------------------------------------------------------------ // | |
/// @brief Chaining for `Future`-returning functors. | |
/// | |
/// @tparam Resolve A functor which returns a `Future`. | |
/// | |
/// @param resolve The functor to call when this one is ready. | |
/// | |
/// @return A `Future` which will be resolved by `resolve`. | |
template< | |
typename Resolve, | |
typename Reject, | |
typename ResolveResult = typename std::result_of<Resolve(T&&)>::type, | |
typename std::enable_if<IsFuture<ResolveResult>::value>::type* = nullptr | |
> | |
Future<typename ResolveResult::result_type> _then(Resolve&& resolve, Reject&& reject); | |
// ------------------------------------------------------------------------------------------ // | |
/// @brief Chaining for value-returning functors (i.e. synchronous ones). | |
/// | |
/// @tparam Resolve A synchronous functor type. | |
/// | |
/// @param resolve A synchronous functor returning some value. | |
/// | |
/// @return A `Future` which will be resolved with the return value from `resolve`. | |
template< | |
typename Resolve, | |
typename Reject, | |
typename ResolveResult = typename std::result_of<Resolve(T&&)>::type, | |
typename std::enable_if< | |
!IsFuture<ResolveResult>::value && | |
!std::is_void<ResolveResult>::value | |
>::type* = nullptr | |
> | |
Future<ResolveResult> _then(Resolve&& resolve, Reject&& reject); | |
// ------------------------------------------------------------------------------------------ // | |
/// @brief Chaining for void-returning synchronous functors. | |
/// | |
/// @tparam Resolve A synchronous functor type. | |
/// | |
/// @param resolve A synchronous functor with no return value. | |
/// | |
/// @return A `Future` which will be resolved `resolve` runs. | |
template< | |
typename Resolve, | |
typename Reject, | |
typename ResolveResult = typename std::result_of<Resolve(T&&)>::type, | |
typename std::enable_if<std::is_void<ResolveResult>::value>::type* = nullptr | |
> | |
Future<> _then(Resolve&& resolve, Reject&& reject); | |
// ------------------------------------------------------------------------------------------ // | |
/// @brief Our internal shared state. | |
typename promise_type::_SharedStatePtr m_state; | |
}; | |
template<> | |
class Promise< void >{ | |
public: | |
/// @brief Default construction. | |
Promise( void ): | |
m_state( new _SharedState() ) | |
{ | |
m_state->resolved = false; | |
m_state->rejected = false; | |
m_state->resolve = nullptr; | |
m_state->reject = nullptr; | |
} | |
// ---------------------------------------------------------------------- // | |
/// @brief No copying! | |
Promise( const Promise& ) = delete; | |
// ---------------------------------------------------------------------- // | |
/// @brief Moves the promise from `other` to `this`. | |
Promise( Promise&& other ): | |
m_state( std::move( other.m_state ) ) | |
{ | |
other.m_state = nullptr; | |
} | |
// ---------------------------------------------------------------------- // | |
/// @brief Returns a future associated with this promise. | |
Future< void > future( void ); | |
// ---------------------------------------------------------------------- // | |
/// @brief Resolves the promise as a success. | |
void resolve( void ){ | |
m_state->resolved = true; | |
if( m_state->resolve ){ | |
m_state->resolve(); | |
} | |
} | |
// ---------------------------------------------------------------------- // | |
/// @brief Rejects the promise as a failure. | |
void reject( const error::Exception& err ){ | |
m_state->rejected = true; | |
if( m_state->reject ){ | |
m_state->reject( err ); | |
} | |
else { | |
throw err; | |
} | |
} | |
// ---------------------------------------------------------------------- // | |
/// @brief Resets the promise's internal state so that it can be reused. | |
/// | |
/// @throws PromiseError If the promise is in an unfinished state. | |
void reset( void ){ | |
if( !is_finished() ){ | |
throw PromiseError( 1, "Cannot reset an unfinished promise." ); | |
} | |
m_state->resolved = false; | |
m_state->rejected = false; | |
m_state->resolve = nullptr; | |
m_state->reject = nullptr; | |
} | |
// ---------------------------------------------------------------------- // | |
/// @brief Indicates if the promise has been resolved. | |
bool is_resolved( void ) const { | |
return m_state->resolved; | |
} | |
// ---------------------------------------------------------------------- // | |
/// @brief Indicates if the promise has been rejected. | |
bool is_rejected( void ) const { | |
return m_state->rejected; | |
} | |
// ---------------------------------------------------------------------- // | |
/// @brief Indicates if the promise has been either resolved or rejected. | |
bool is_finished( void ) const { | |
return is_resolved() || is_rejected(); | |
} | |
// ---------------------------------------------------------------------- // | |
/// @brief No copying! | |
Promise& operator=( const Promise& ) = delete; | |
// ---------------------------------------------------------------------- // | |
/// @brief Moves the promise from `other` into `this`. | |
Promise& operator=( Promise&& other ){ | |
m_state = std::move( other.m_state ); | |
other.m_state = nullptr; | |
return *this; | |
} | |
private: | |
template< typename Type > | |
friend class ::capy::event::Future; | |
// ---------------------------------------------------------------------- // | |
/// @brief The container for the shared state between promises and futures. | |
struct _SharedState { | |
std::atomic_bool resolved; | |
std::atomic_bool rejected; | |
std::function< void( void ) > resolve; | |
std::function< void( const error::Exception& ) > reject; | |
}; | |
typedef std::shared_ptr< _SharedState > _SharedStatePtr; | |
// ---------------------------------------------------------------------- // | |
/// @brief The state of the promise. | |
_SharedStatePtr m_state; | |
}; | |
// -------------------------------------------------------------------------- // | |
template<> | |
class Future< void >{ | |
public: | |
/// @brief The type promised by this future. | |
typedef void result_type; | |
/// @brief The type of Promise that made this future. | |
typedef Promise< void > promise_type; | |
// ---------------------------------------------------------------------- // | |
template< typename Func > | |
auto then( Func&& func ){ | |
return then( std::forward< Func >( func ), nullptr ); | |
} | |
// ---------------------------------------------------------------------- // | |
template< typename Result, typename Func > | |
auto then( Func&& func ){ | |
return then< Result >( std::forward< Func >( func ), nullptr ); | |
} | |
// ---------------------------------------------------------------------- // | |
template< typename Resolve, typename Reject > | |
auto then( Resolve&& resolve, Reject&& reject ){ | |
return _then( | |
std::forward< Resolve >( resolve ), | |
std::forward< Reject >( reject ) | |
); | |
} | |
// ---------------------------------------------------------------------- // | |
template< typename Result, typename Resolve, typename Reject > | |
auto then( Resolve&& resolve, Reject&& reject ){ | |
return _then< Result >( | |
std::forward< Resolve >( resolve ), | |
std::forward< Reject >( reject ) | |
); | |
} | |
// ---------------------------------------------------------------------- // | |
/// @brief Connects this promise to the one provided. | |
/// | |
/// @param promise The promise to resolve/reject with this one. | |
void then( promise_type&& promise ); | |
// ---------------------------------------------------------------------- // | |
private: | |
template< typename Type > | |
friend class ::capy::event::Promise; | |
// ---------------------------------------------------------------------- // | |
/// @brief Only `Promise`s can construct us. | |
/// | |
/// @param state The shared state to associate with. | |
Future( const typename promise_type::_SharedStatePtr& state ): | |
m_state( state ) | |
{} | |
// ---------------------------------------------------------------------- // | |
/// @brief Chaining for generic functors. | |
/// | |
/// @tparam Result The type given functor promises. | |
/// @tparam Resolve A functor type that can take a `Promise&&` as its parameter. | |
/// | |
/// @param resolve The functor to call when this one is resolved. | |
/// | |
/// @return A new future, for when the provided `resolve` completes its action. | |
template< | |
typename Result, | |
typename Resolve, | |
typename Reject, | |
typename = typename std::result_of< Resolve( Promise< Result >&& ) >::type | |
> | |
Future< Result > _then( Resolve&& resolve, Reject&& reject ); | |
// ---------------------------------------------------------------------- // | |
/// @brief Chaining for generic functors promising nothing. | |
/// | |
/// @tparam Resolve A functor type that can take a `Promise&&` as its parameter. | |
/// | |
/// @param resolve The functor to call when this one is resolved. | |
/// | |
/// @return A new future, for when the provided `resolve` completes its action. | |
template< | |
typename Resolve, | |
typename Reject, | |
typename = typename std::result_of< Resolve( Promise<>&& ) >::type | |
> | |
Future<> _then( Resolve&& resolve, Reject&& reject ); | |
// ---------------------------------------------------------------------- // | |
/// @brief Chaining for `Future`-returning functors. | |
/// | |
/// @tparam Resolve A functor which returns a `Future`. | |
/// | |
/// @param resolve The functor to call when this one is ready. | |
/// | |
/// @return A `Future` which will be resolved by `resolve`. | |
template< | |
typename Resolve, | |
typename Reject, | |
typename ResolveResult = typename std::result_of< Resolve() >::type, | |
typename std::enable_if< IsFuture< ResolveResult >::value >::type* = nullptr | |
> | |
Future< typename ResolveResult::result_type > _then( Resolve&& resolve, Reject&& reject ); | |
// ---------------------------------------------------------------------- // | |
/// @brief Chaining for value-returning functors (i.e. synchronous ones). | |
/// | |
/// @tparam Resolve A synchronous functor type. | |
/// | |
/// @param resolve A synchronous functor returning some value. | |
/// | |
/// @return A `Future` which will be resolved with the return value from `resolve`. | |
template< | |
typename Resolve, | |
typename Reject, | |
typename ResolveResult = typename std::result_of< Resolve() >::type, | |
typename std::enable_if< | |
!IsFuture< ResolveResult >::value && | |
!std::is_void< ResolveResult >::value | |
>::type* = nullptr | |
> | |
Future< ResolveResult > _then( Resolve&& resolve, Reject&& reject ); | |
// ---------------------------------------------------------------------- // | |
/// @brief Chaining for void-returning synchronous functors. | |
/// | |
/// @tparam Resolve A synchronous functor type. | |
/// | |
/// @param resolve A synchronous functor with no return value. | |
/// | |
/// @return A `Future` which will be resolved `resolve` runs. | |
template< | |
typename Resolve, | |
typename Reject, | |
typename ResolveResult = typename std::result_of< Resolve() >::type, | |
typename std::enable_if< std::is_void< ResolveResult >::value >::type* = nullptr | |
> | |
Future<> _then( Resolve&& resolve, Reject&& reject ); | |
// ---------------------------------------------------------------------- // | |
/// @brief Our internal shared state. | |
typename promise_type::_SharedStatePtr m_state; | |
}; | |
template< typename T > | |
inline Future< T > Promise< T >::future( void ){ | |
return Future< T >( m_state ); | |
} | |
// ---------------------------------------------------------------------------------------------- // | |
inline Future< void > Promise< void >::future( void ){ | |
return Future< void >( m_state ); | |
} | |
// ---------------------------------------------------------------------------------------------- // | |
template< typename T > | |
template< typename Result, typename Resolve, typename Reject, typename > | |
Future< Result > Future< T >::_then( Resolve&& resolve, Reject&& reject ){ | |
auto next = std::make_shared< Promise< Result > >(); | |
auto prev = m_state; | |
m_state->resolve = [ resolve, prev, next ]( T&& value ) mutable { | |
resolve( std::move( value ), std::move( *next ) ); | |
prev->reject = nullptr; | |
prev.reset(); | |
}; | |
typedef std::function< void( const error::Exception& ) > RejectHandler; | |
RejectHandler rejectHandler; | |
if( std::is_same< std::nullptr_t, Reject >::value ){ | |
rejectHandler = [ next ]( const error::Exception& err ){ | |
next->reject( err ); | |
}; | |
} | |
else { | |
rejectHandler = std::forward< Reject >( reject ); | |
} | |
m_state->reject = [ rejectHandler, prev, next ]( | |
const error::Exception& err | |
) mutable { | |
rejectHandler( err ); | |
prev->resolve = nullptr; | |
prev.reset(); | |
}; | |
return next->future(); | |
} | |
// ---------------------------------------------------------------------------------------------- // | |
template< typename T > | |
template< typename Resolve, typename Reject, typename > | |
inline Future<> Future< T >::_then( Resolve&& resolve, Reject&& reject ){ | |
return then< void >( | |
std::forward< Resolve >( resolve ), | |
std::forward< Reject >( reject ) | |
); | |
} | |
// ---------------------------------------------------------------------------------------------- // | |
template< typename T > | |
template< | |
typename Resolve, | |
typename Reject, | |
typename ResolveResult, | |
typename std::enable_if< IsFuture< ResolveResult >::value >::type* | |
> | |
Future< typename ResolveResult::result_type > Future< T >::_then( Resolve&& resolve, Reject&& reject ){ | |
typedef typename ResolveResult::result_type Result; | |
return then< Result >( | |
[ resolve ]( T&& value, Promise< Result >&& promise ) mutable { | |
resolve( std::move( value ) ).then( std::move( promise ) ); | |
}, | |
std::forward< Reject >( reject ) | |
); | |
} | |
// ---------------------------------------------------------------------------------------------- // | |
template< typename T > | |
template< | |
typename Resolve, | |
typename Reject, | |
typename ResolveResult, | |
typename std::enable_if< | |
!IsFuture< ResolveResult >::value && | |
!std::is_void< ResolveResult >::value | |
>::type* | |
> | |
Future< ResolveResult > Future< T >::_then( Resolve&& resolve, Reject&& reject ){ | |
return then< ResolveResult >( | |
[ resolve ]( T&& value, Promise< ResolveResult >&& promise ) mutable { | |
try { | |
promise.resolve( resolve( std::move( value ) ) ); | |
} | |
catch( const error::Exception& err ){ | |
promise.reject( err ); | |
} | |
}, | |
std::forward< Reject >( reject ) | |
); | |
} | |
// ---------------------------------------------------------------------------------------------- // | |
template< typename T > | |
template< | |
typename Resolve, | |
typename Reject, | |
typename ResolveResult, | |
typename std::enable_if< std::is_void< ResolveResult >::value >::type* | |
> | |
Future<> Future< T >::_then( Resolve&& resolve, Reject&& reject ){ | |
return then( | |
[ resolve ]( T&& value, Promise<>&& promise ){ | |
try { | |
resolve( std::move( value ) ); | |
} | |
catch( const error::Exception& err ){ | |
promise.reject( err ); | |
return; | |
} | |
promise.resolve(); | |
}, | |
std::forward< Reject >( reject ) | |
); | |
} | |
// ---------------------------------------------------------------------------------------------- // | |
template< typename T > | |
void Future< T >::then( promise_type&& promise ){ | |
auto next = std::make_shared< promise_type >( std::move( promise ) ); | |
auto prev = m_state; | |
m_state->resolve = [ prev, next ]( T&& value ) mutable { | |
next->resolve( std::move( value ) ); | |
prev->reject = nullptr; | |
prev.reset(); | |
}; | |
m_state->reject = [ prev, next ]( const error::Exception& err ) mutable { | |
next->reject( err ); | |
prev->resolve = nullptr; | |
prev.reset(); | |
}; | |
} | |
// ---------------------------------------------------------------------------------------------- // | |
template< typename Result, typename Resolve, typename Reject, typename > | |
Future< Result > Future< void >::_then( Resolve&& resolve, Reject&& reject ){ | |
auto next = std::make_shared< Promise< Result > >(); | |
auto prev = m_state; | |
m_state->resolve = [ resolve, prev, next ]() mutable { | |
resolve( std::move( *next ) ); | |
prev->reject = nullptr; | |
prev.reset(); | |
}; | |
typedef std::function< void( const error::Exception& ) > RejectHandler; | |
RejectHandler rejectHandler; | |
if( std::is_same< std::nullptr_t, Reject >::value ){ | |
rejectHandler = [ next ]( const error::Exception& err ){ | |
next->reject( err ); | |
}; | |
} | |
else { | |
rejectHandler = std::forward< Reject >( reject ); | |
} | |
m_state->reject = [ rejectHandler, prev, next ]( | |
const error::Exception& err | |
) mutable { | |
rejectHandler( err ); | |
prev->resolve = nullptr; | |
prev.reset(); | |
}; | |
return next->future(); | |
} | |
// ---------------------------------------------------------------------------------------------- // | |
template< typename Resolve, typename Reject, typename > | |
Future<> Future< void >::_then( Resolve&& resolve, Reject&& reject ){ | |
return then< void >( | |
std::forward< Resolve >( resolve ), | |
std::forward< Reject >( reject ) | |
); | |
} | |
// ---------------------------------------------------------------------------------------------- // | |
template< | |
typename Resolve, | |
typename Reject, | |
typename ResolveResult, | |
typename std::enable_if< IsFuture< ResolveResult >::value >::type* | |
> | |
Future< typename ResolveResult::result_type > Future< void >::_then( Resolve&& resolve, Reject&& reject ){ | |
typedef typename ResolveResult::result_type Result; | |
return then< Result >( | |
[ resolve ]( Promise< Result >&& promise ){ | |
resolve().then( std::move( promise ) ); | |
}, | |
std::forward< Reject >( reject ) | |
); | |
} | |
// ---------------------------------------------------------------------------------------------- // | |
template< | |
typename Resolve, | |
typename Reject, | |
typename ResolveResult, | |
typename std::enable_if< | |
!IsFuture< ResolveResult >::value && | |
!std::is_void< ResolveResult >::value | |
>::type* | |
> | |
Future< ResolveResult > Future< void >::_then( Resolve&& resolve, Reject&& reject ){ | |
return then< ResolveResult >( | |
[ resolve ]( Promise< ResolveResult >&& promise ){ | |
try { | |
promise.resolve( resolve() ); | |
} | |
catch( const error::Exception& err ){ | |
promise.reject( err ); | |
} | |
}, | |
std::forward< Reject >( reject ) | |
); | |
} | |
// ---------------------------------------------------------------------------------------------- // | |
template< | |
typename Resolve, | |
typename Reject, | |
typename ResolveResult, | |
typename std::enable_if< std::is_void< ResolveResult >::value >::type* | |
> | |
Future< void > Future< void >::_then( Resolve&& resolve, Reject&& reject ){ | |
return then< void >( | |
[ resolve ]( Promise< void >&& promise ){ | |
try { | |
resolve(); | |
} | |
catch( const error::Exception& err ){ | |
promise.reject( err ); | |
return; | |
} | |
promise.resolve(); | |
}, | |
std::forward< Reject >( reject ) | |
); | |
} | |
// ---------------------------------------------------------------------------------------------- // | |
inline void Future< void >::then( promise_type&& promise ){ | |
auto next = std::make_shared< promise_type >( std::move( promise ) ); | |
auto prev = m_state; | |
m_state->resolve = [ prev, next ]() mutable { | |
next->resolve(); | |
prev->reject = nullptr; | |
prev.reset(); | |
}; | |
m_state->reject = [ prev, next ]( const error::Exception& err ) mutable { | |
next->reject( err ); | |
prev->resolve = nullptr; | |
prev.reset(); | |
}; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment