Chain a :class:`~asyncio.Future` to an existing ``future``.

    This function `chain` the ``next`` future to an existing ``future``.
    When the input ``future`` receive a result the optional
    ``callback`` is executed and its result set as the results of ``next``.
    If an exception occurs the optional ``errback`` is executed.

    :param future: the original :class:`~asyncio.Future` (can be a coroutine)
    :param callback: optional callback to execute on the result of ``future``
    :param errback: optional callback to execute on the exception of ``future``
    :param next: optional :class:`~asyncio.Future` to chain.
        If not provided a new future is created
    :return: the future ``next``

def chain_future(future, callback=None, errback=None, next=None):
    '''Chain a :class:`~asyncio.Future` to an existing ``future``.

    This function `chain` the ``next`` future to an existing ``future``.
    When the input ``future`` receive a result the optional
    ``callback`` is executed and its result set as the results of ``next``.
    If an exception occurs the optional ``errback`` is executed.

    :param future: the original :class:`~asyncio.Future` (can be a coroutine)
    :param callback: optional callback to execute on the result of ``future``
    :param errback: optional callback to execute on the exception of ``future``
    :param next: optional :class:`~asyncio.Future` to chain.
        If not provided a new future is created
    :return: the future ``next``
    '''
    loop = next._loop if next else None
    future = ensure_future(future, loop=loop)
    if next is None:
        next = create_future(future._loop)

    def _callback(fut):
        try:
            try:
                result = future.result()
            except Exception as exc:
                if errback:
                    result = errback(exc)
                    exc = None
                else:
                    raise
            else:
                if callback:
                    result = callback(result)
        except Exception as exc:
            next.set_exception(exc)
        else:
            if isinstance(result, Future):
                chain_future(result, next=next)
            else:
                next.set_result(result)

    future.add_done_callback(_callback)
    return next