# Path: guv/hubs/switch.py
# def trampoline(fd, evtype, timeout=None, timeout_exc=Timeout):
#     """Jump from the current greenlet to the hub and wait until the given file descriptor is ready
#     for I/O, or the specified timeout elapses
# 
#     If the specified `timeout` elapses before the socket is ready to read or write, `timeout_exc`
#     will be raised instead of :func:`trampoline()` returning normally.
# 
#     When the specified file descriptor is ready for I/O, the hub internally calls the callback to
#     switch back to the current (this) greenlet.
# 
#     Conditions:
# 
#     - must not be called from the hub greenlet (can be called from any other greenlet)
#     - `evtype` must be either :attr:`~guv.const.READ` or :attr:`~guv.const.WRITE` (not possible to
#       watch for  both  simultaneously)
# 
#     :param int fd: file descriptor
#     :param int evtype: either the constant :attr:`~guv.const.READ` or :attr:`~guv.const.WRITE`
#     :param float timeout: (optional) maximum time to wait in seconds
#     :param Exception timeout_exc: (optional) timeout Exception class
#     """
#     #: :type: AbstractHub
#     hub = get_hub()
#     current = greenlet.getcurrent()
# 
#     assert hub is not current, 'do not call blocking functions from the mainloop'
#     assert isinstance(fd, int)
# 
#     timer = None
#     if timeout is not None:
#         def _timeout(exc):
#             # timeout has passed
#             current.throw(exc)
# 
#         timer = hub.schedule_call_global(timeout, _timeout, timeout_exc)
# 
#     try:
#         # add a watcher for this file descriptor
#         listener = hub.add(evtype, fd, current.switch, current.throw)
# 
#         # switch to the hub
#         try:
#             return hub.switch()
#         finally:
#             # log.debug('(trampoline finally) remove listener for fd: {}'.format(fd))
#             hub.remove(listener)
#     finally:
#         if timer is not None:
#             timer.cancel()
# 
# Path: guv/const.py
# READ = 1
# 
# WRITE = 2


import psycopg2
from psycopg2 import extensions
from ..hubs import trampoline
from ..const import READ, WRITE
"""A wait callback to allow psycopg2 cooperation with guv

Use :func:`make_psycopg_green()` to enable guv support in psycopg2.
"""




def psycopg2_wait_cb(conn, timeout=-1):
    """A wait callback to trigger a yield while waiting for the database to respond
    """
    while True:
        state = conn.poll()
        if state == extensions.POLL_OK:
            break
        elif state == extensions.POLL_READ:
            trampoline(conn.fileno(), READ)
        elif state == extensions.POLL_WRITE:

# Path: guv/hubs/switch.py
# def trampoline(fd, evtype, timeout=None, timeout_exc=Timeout):
#     """Jump from the current greenlet to the hub and wait until the given file descriptor is ready
#     for I/O, or the specified timeout elapses
# 
#     If the specified `timeout` elapses before the socket is ready to read or write, `timeout_exc`
#     will be raised instead of :func:`trampoline()` returning normally.
# 
#     When the specified file descriptor is ready for I/O, the hub internally calls the callback to
#     switch back to the current (this) greenlet.
# 
#     Conditions:
# 
#     - must not be called from the hub greenlet (can be called from any other greenlet)
#     - `evtype` must be either :attr:`~guv.const.READ` or :attr:`~guv.const.WRITE` (not possible to
#       watch for  both  simultaneously)
# 
#     :param int fd: file descriptor
#     :param int evtype: either the constant :attr:`~guv.const.READ` or :attr:`~guv.const.WRITE`
#     :param float timeout: (optional) maximum time to wait in seconds
#     :param Exception timeout_exc: (optional) timeout Exception class
#     """
#     #: :type: AbstractHub
#     hub = get_hub()
#     current = greenlet.getcurrent()
# 
#     assert hub is not current, 'do not call blocking functions from the mainloop'
#     assert isinstance(fd, int)
# 
#     timer = None
#     if timeout is not None:
#         def _timeout(exc):
#             # timeout has passed
#             current.throw(exc)
# 
#         timer = hub.schedule_call_global(timeout, _timeout, timeout_exc)
# 
#     try:
#         # add a watcher for this file descriptor
#         listener = hub.add(evtype, fd, current.switch, current.throw)
# 
#         # switch to the hub
#         try:
#             return hub.switch()
#         finally:
#             # log.debug('(trampoline finally) remove listener for fd: {}'.format(fd))
#             hub.remove(listener)
#     finally:
#         if timer is not None:
#             timer.cancel()
# 
# Path: guv/const.py
# READ = 1
# 
# WRITE = 2


# Path: guv/support/psycopg2_patcher.py
import psycopg2
from psycopg2 import extensions
from ..hubs import trampoline
from ..const import READ, WRITE

"""A wait callback to allow psycopg2 cooperation with guv

Use :func:`make_psycopg_green()` to enable guv support in psycopg2.
"""




def psycopg2_wait_cb(conn, timeout=-1):
    """A wait callback to trigger a yield while waiting for the database to respond
    """
    while True:
        state = conn.poll()
        if state == extensions.POLL_OK:
            break
        elif state == extensions.POLL_READ:
            trampoline(conn.fileno(), READ)
        elif state == extensions.POLL_WRITE:

            trampoline(conn.fileno(), WRITE)