::

                 +----------+
        send --> |  Queue   |
                 | (buffer) | --> recv
                 +----------+

    A Queue may also only have exactly one sender and recver. A Queue however
    has a fifo buffer of a custom size. Sends to the Queue won't block until
    the buffer becomes full::

        h = vanilla.Hub()
        q = h.queue(1)
        q.send(1)      # safe from deadlock
        # q.send(1)    # this would deadlock however as the queue only has a
                       # buffer size of 1
        q.recv()       # returns 1

def Queue(hub, size):
    """
    ::

                 +----------+
        send --> |  Queue   |
                 | (buffer) | --> recv
                 +----------+

    A Queue may also only have exactly one sender and recver. A Queue however
    has a fifo buffer of a custom size. Sends to the Queue won't block until
    the buffer becomes full::

        h = vanilla.Hub()
        q = h.queue(1)
        q.send(1)      # safe from deadlock
        # q.send(1)    # this would deadlock however as the queue only has a
                       # buffer size of 1
        q.recv()       # returns 1
    """
    assert size > 0

    def main(upstream, downstream, size):
        queue = collections.deque()

        while True:
            if downstream.halted:
                # no one is downstream, so shutdown
                upstream.close()
                return

            watch = []
            if queue:
                watch.append(downstream)
            else:
                # if the buffer is empty, and no one is upstream, shutdown
                if upstream.halted:
                    downstream.close()
                    return

            # if are upstream is still available, and there is spare room in
            # the buffer, watch upstream as well
            if not upstream.halted and len(queue) < size:
                watch.append(upstream)

            try:
                ch, item = hub.select(watch)
            except vanilla.exception.Halt:
                continue

            if ch == upstream:
                queue.append(item)

            elif ch == downstream:
                item = queue.popleft()
                downstream.send(item)

    upstream = hub.pipe()
    downstream = hub.pipe()

    # TODO: rethink this
    old_connect = upstream.sender.connect

    def connect(recver):
        old_connect(recver)
        return downstream.recver

    upstream.sender.connect = connect

    hub.spawn(main, upstream.recver, downstream.sender, size)
    return Pair(upstream.sender, downstream.recver)