raise "OMG" if RUBY_VERSION < "1.9.0" class Go @@waiting = [] @@current = nil @@creation = [] class Channel Msg = Struct.new :value, :p, :blocker def initialize(bufsize=1) @bufsize = bufsize @msgbuf = [] @send = [] @recv = [] end def << value _send_msg Msg.new(value) end def send(&p) _send_msg Msg.new(nil, p) end def ~ unless @msgbuf.empty? msg = @msgbuf.shift Go.schedule(msg.blocker, nil) if msg.blocker return _value_of msg end @recv << Go.current_fiber Fiber.yield end def _send_msg(msg) @msgbuf << msg if !@recv.empty? # ASSERT @msgbuf.first.blocker.nil? Go.schedule(@recv.shift, _value_of(@msgbuf.shift)) else @msgbuf.size + 1 >= @bufsize msg.blocker = Go.current_fiber Fiber.yield end end def _value_of msg msg.p ? msg.p[] : msg.value end end def self.go(&p) @@creation << p end def self.chan Channel.new end def self.schedule(fiber, arg) @@waiting << [fiber, arg] end def self.current_fiber @@current_fiber end def self.proceed(&p) go &p if p loop { unless @@creation.empty? @@creation.each {|p| @@waiting << [Fiber.new(&p), nil] } @@creation = [] end break if @@waiting.empty? a = @@waiting @@waiting = [] a.each {|pair| @@current_fiber = pair.first pair.first.resume(pair.last) } } end end ## MAIN ## def fibs ch = Go::chan Go::go { ch << 1 ch << 1 ch0 = fibs ch1 = fibs ~ch1 loop { ch.send { ~ch0 + ~ch1 } } } ch end Go.proceed { ch = fibs 10.times { p [~ch] } }