~singpolyma/em_promise.rb

b3b5eba124753c4cc94837b7f373366ef6b60638 — Stephen Paul Weber 2 months ago 47034fc
Allow integration by other fiber-sync implementations

Move the magic sync-and-pump code from #wait into Trampoline.yield.  This allows
anyone else doing fiber-sync code to use Trampoline.yield instead of Fiber.yield
in their implementation to allow promises to keep resolving while they wait.
1 files changed, 32 insertions(+), 19 deletions(-)

M lib/em_promise.rb
M lib/em_promise.rb => lib/em_promise.rb +32 -19
@@ 8,28 8,51 @@ class EMPromise < Promise
	class Trampoline
		attr_accessor :ready

		def initialize
		class SubmittedBlock
			def initialize(blk)
				@blk = blk
			end

			def call(*args, **kwargs, &blk)
				@blk.call(*args, **kwargs, &blk)
			end
		end

		def initialize(&initial_blk)
			@ready = true
			@fiber = Fiber.new do |blk|
				Thread.current[:_em_promise_trampoline] = self
				loop do
					self.ready = false
					result = blk.call
					self.ready = true
					blk = Fiber.yield result
				end
				self.ready = false
				Trampoline.yield(blk.call)
			end
			@fiber.resume(&initial_blk) if initial_blk
		end

		def submit(&blk)
			EM.next_tick do
				if ready
					@fiber.resume(blk)
					@fiber.resume(SubmittedBlock.new(blk))
				else
					submit(&blk)
				end
			end
		end

		def self.yield(arg=nil)
			tramp = Thread.current[:_em_promise_trampoline]
			raise "Trampoline already ready?" if tramp&.ready

			loop do
				tramp&.ready = true
				blk = Fiber.yield arg
				tramp&.ready = false
				if blk.is_a?(SubmittedBlock)
					arg = blk.call
				else
					return arg
				end
			end
		end
	end

	# Make sure that self.class.new inherits the trampoline


@@ 73,17 96,7 @@ class EMPromise < Promise
		self.then(resume, resume)

		# We might be in a trampoline, so keep that going
		tramp = Thread.current[:_em_promise_trampoline]
		raise "Trampoline already ready?" if tramp&.ready

		result = nil
		loop do
			tramp&.ready = true
			blk = Fiber.yield result
			tramp&.ready = false
			result = blk&.call
			break unless blk
		end
		Trampoline.yield
	end

	def self.reject(e)