docs: def coroutine(f):
      """
      Implementation of a coroutine.
  
      Use as a decorator:
      @coroutine
      def foo():
          result = yield somePromise
  
      The function passed should be a generator yielding instances of the Promise class
      (or compatible).
      The coroutine waits for the Promise to resolve and sends the result (or the error)
      back into the generator function.
      This simulates sequential execution which in reality can be asynchonous.
      """
  
      @functools.wraps(f)
      def _coroutine(*args, **kwargs):
          def _resolver(resolve, reject):
              try:
                  generator = f(*args, **kwargs)
              except BaseException as e:
                  # Special case for a function that throws immediately
                  reject(e)
              else:
                  # Special case for a function that returns immediately
                  if not isinstance(generator, types.GeneratorType):
                      resolve(generator)
                  else:
                      def _step(previous, previous_type):
                          element = None
  
                          try:
                              if previous_type == None:
                                  element = next(generator)
                              elif previous_type:
                                  element = generator.send(previous)
                              else:
                                  if not isinstance(previous, BaseException):
                                      previous = RejectedException(previous)
  
                                  element = generator.throw(previous)
                          except StopIteration as e:
                              resolve(getattr(e, "value", None))
                          except ReturnValueException as e:
                              resolve(e.value)
                          except BaseException as e:
                              reject(e)
                          else:
                              try:
                                  element.then(
                                      lambda value  : _step(value, True),
                                      lambda reason : _step(reason, False)
                                  )
                              except AttributeError:
                                  reject(InvalidCoroutineException(element))
  
                      _step(None, None)
  
          return Promise(_resolver)
  
      return _coroutine