Files
news.gitea.happylizard.me/bin/gems/async-2.23.0/lib/async/queue.rb
T
pizza2d1 4cee170d66
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 9s
Add bin and edit workflow
2026-09-16 13:11:16 -06:00

172 lines
4.0 KiB
Ruby

# frozen_string_literal: true
# Released under the MIT License.
# Copyright, 2018-2024, by Samuel Williams.
# Copyright, 2019, by Ryan Musgrave.
# Copyright, 2020-2022, by Bruno Sutic.
require_relative "notification"
module Async
# A queue which allows items to be processed in order.
#
# It has a compatible interface with {Notification} and {Condition}, except that it's multi-value.
#
# @public Since *Async v1*.
class Queue
# Create a new queue.
#
# @parameter parent [Interface(:async) | Nil] The parent task to use for async operations.
# @parameter available [Notification] The notification to use for signaling when items are available.
def initialize(parent: nil, available: Notification.new)
@items = []
@parent = parent
@available = available
end
# @attribute [Array] The items in the queue.
attr :items
# @returns [Integer] The number of items in the queue.
def size
@items.size
end
# @returns [Boolean] Whether the queue is empty.
def empty?
@items.empty?
end
# Add an item to the queue.
def push(item)
@items << item
@available.signal unless self.empty?
end
# Compatibility with {::Queue#push}.
def <<(item)
self.push(item)
end
# Add multiple items to the queue.
def enqueue(*items)
@items.concat(items)
@available.signal unless self.empty?
end
# Remove and return the next item from the queue.
def dequeue
while @items.empty?
@available.wait
end
@items.shift
end
# Compatibility with {::Queue#pop}.
def pop
self.dequeue
end
# Process each item in the queue.
#
# @asynchronous Executes the given block concurrently for each item.
#
# @parameter arguments [Array] The arguments to pass to the block.
# @parameter parent [Interface(:async) | Nil] The parent task to use for async operations.
# @parameter options [Hash] The options to pass to the task.
# @yields {|task| ...} When the system is idle, the block will be executed in a new task.
def async(parent: (@parent or Task.current), **options, &block)
while item = self.dequeue
parent.async(item, **options, &block)
end
end
# Enumerate each item in the queue.
def each
while item = self.dequeue
yield item
end
end
# Signal the queue with a value, the same as {#enqueue}.
def signal(value = nil)
self.enqueue(value)
end
# Wait for an item to be available, the same as {#dequeue}.
def wait
self.dequeue
end
end
# A queue which limits the number of items that can be enqueued.
# @public Since *Async v1*.
class LimitedQueue < Queue
# Create a new limited queue.
#
# @parameter limit [Integer] The maximum number of items that can be enqueued.
# @parameter full [Notification] The notification to use for signaling when the queue is full.
def initialize(limit = 1, full: Notification.new, **options)
super(**options)
@limit = limit
@full = full
end
# @attribute [Integer] The maximum number of items that can be enqueued.
attr :limit
# @returns [Boolean] Whether trying to enqueue an item would block.
def limited?
@items.size >= @limit
end
# Add an item to the queue.
#
# If the queue is full, this method will block until there is space available.
#
# @parameter item [Object] The item to add to the queue.
def push(item)
while limited?
@full.wait
end
super
end
# Add multiple items to the queue.
#
# If the queue is full, this method will block until there is space available.
#
# @parameter items [Array] The items to add to the queue.
def enqueue(*items)
while !items.empty?
while limited?
@full.wait
end
available = @limit - @items.size
@items.concat(items.shift(available))
@available.signal unless self.empty?
end
end
# Remove and return the next item from the queue.
#
# If the queue is empty, this method will block until an item is available.
#
# @returns [Object] The next item in the queue.
def dequeue
item = super
@full.signal
return item
end
end
end