class Async::Node

A node in a tree, used for implementing the task hierarchy.

def add_child(child)

def add_child(child)
 ||= Children.new
.append(child)
_parent(self)

def annotate(annotation)

def annotate(annotation)
	if block_given?
		previous_annotation = @annotation
		@annotation = annotation
		yield
		@annotation = previous_annotation
	else
		@annotation = annotation
	end
end

def backtrace(*arguments)

def backtrace(*arguments)
	nil
end

def children?

@returns [Boolean]
Whether this node has any children.
def children?
	@children && !@children.empty?
end

def consume

the parent.
If the node has a parent, and is {finished?}, then remove this node from
def consume
	if parent = @parent and finished?
		parent.remove_child(self)
		
		# If we have children, then we need to move them to our the parent if they are not finished:
		if @children
			while child = @children.shift
				if child.finished?
					child.set_parent(nil)
				else
					parent.add_child(child)
				end
			end
			
			@children = nil
		end
		
		parent.consume
	end
end

def description

def description
	@object_name ||= "#{self.class}:#{format '%#018x', object_id}#{@transient ? ' transient' : nil}"
	
	if @annotation
		"#{@object_name} #{@annotation}"
	elsif line = self.backtrace(0, 1)&.first
		"#{@object_name} #{line}"
	else
		@object_name
	end
end

def finished?

@returns [Boolean]

Whether the node can be consumed (deleted) safely. By default, checks if the children set is empty.
def finished?
	@children.nil? || @children.finished?
end

def initialize(parent = nil, annotation: nil, transient: false)

@parameter parent [Node | Nil] This node will attach to the given parent.
Create a new node in the tree.
def initialize(parent = nil, annotation: nil, transient: false)
	@parent = nil
	@children = nil
	
	@annotation = annotation
	@object_name = nil
	
	@transient = transient
	
	@head = nil
	@tail = nil
	
	if parent
		parent.add_child(self)
	end
end

def parent=(parent)

@returns [Node] Itself.
@parameter parent [Node | Nil] The parent to attach to, or nil to detach.

Change the parent of this node.
def parent=(parent)
	return if @parent.equal?(parent)
	
	if @parent
		@parent.remove_child(self)
		@parent = nil
	end
	
	if parent
		parent.add_child(self)
	end
	
	return self
end

def print_backtrace(out, indent, node)

def print_backtrace(out, indent, node)
	if backtrace = node.backtrace
		backtrace.each_with_index do |line, index|
			out.puts "#{indent}#{index.zero? ? "→ " : "  "}#{line}"
		end
	end
end

def print_hierarchy(out = $stdout, backtrace: true)

def print_hierarchy(out = $stdout, backtrace: true)
	self.traverse do |node, level|
		indent = "\t" * level
		
		out.puts "#{indent}#{node}"
		
		print_backtrace(out, indent, node) if backtrace
	end
end

def remove_child(child)

def remove_child(child)
.remove(child)
_parent(nil)

def root

@returns [Node] the root node in the hierarchy.
def root
	@parent&.root || self
end

def set_parent(parent)

def set_parent(parent)
 parent

def stop(later = false)

@parameter later [Boolean] Whether to defer stopping until some point in the future.

Attempt to stop the current node immediately, including all non-transient children. Invokes {#stop_children} to stop all children.
def stop(later = false)
	# The implementation of this method may defer calling `stop_children`.
	stop_children(later)
end

def stop_children(later = false)

Attempt to stop all non-transient children.
def stop_children(later = false)
en&.each do |child|
stop(later) unless child.transient?

def stopped?

def stopped?
	@children.nil?
end

def terminate

Immediately terminate all children tasks, including transient tasks. Internally invokes `stop(false)` on all children. This should be considered a last ditch effort and is used when closing the scheduler.
def terminate
	# Attempt to stop the current task immediately, and all children:
	stop(false)
	
	# If that doesn't work, take more serious action:
	@children&.each do |child|
		child.terminate
	end
end

def to_s

def to_s
	"\#<#{self.description}>"
end

def transient?

parent task from finishing.
is not directly related to the parent task, and should not prevent the
a child task which is pruning a connection pool is transient, because it
internal to an object rather than explicit user concurrency. For example,
when determining if a node is finished. This is useful for tasks which are
Represents whether a node is transient. Transient nodes are not considered
def transient?
	@transient
end

def traverse(&block)

@yields {|node, level| ...} The node and the level relative to the given root.
@returns [Enumerator] An enumerator which will traverse the tree if no block is given.

Traverse the task tree.
def traverse(&block)
	return enum_for(:traverse) unless block_given?
	
	self.traverse_recurse(&block)
end

def traverse_recurse(level = 0, &block)

def traverse_recurse(level = 0, &block)
f, level
&.each do |child|
averse_recurse(level + 1, &block)