Skip to content

Instantly share code, notes, and snippets.

@mbj
Last active August 29, 2015 14:10
Show Gist options
  • Save mbj/3f6db32b5ba7349401ac to your computer and use it in GitHub Desktop.
Save mbj/3f6db32b5ba7349401ac to your computer and use it in GitHub Desktop.
My minimal 135loc (stripped) actor implementation powering mutant
require 'concord'
module Actor
class ProtocolError < RuntimeError
end # ProtocolError
Undefined = Class.new do
INSPECT = 'Actor::Undefined'.freeze
def inspect
INSPECT
end
end.new
class Message
include Concord::Public.new(:type, :payload)
def self.new(_type, _payload = Undefined)
super
end
end # Message
class Binding
include Concord.new(:actor, :other)
def call(type)
other.call(Message.new(type, actor.sender))
message = actor.receiver.call
fail ProtocolError, "Expected #{type} but got #{message.type}" unless type.equal?(message.type)
message.payload
end
end # Binding
class Actor
include Concord.new(:thread, :mailbox)
def initialize(*)
super
@sender = mailbox.sender(thread)
end
attr_reader :sender
def receiver
mailbox.receiver
end
def bind(other)
Binding.new(self, other)
end
end # Actor
class Env
include Concord.new(:thread_root)
def spawn
mailbox = Mailbox.new
thread = thread_root.new do
yield mailbox.actor(thread_root.current)
end
mailbox.sender(thread)
end
def current
Mailbox.new.actor(thread_root.current)
end
end # Env
class Mailbox
def initialize
@mutex = Mutex.new
@messages = []
@receiver = Receiver.new(@mutex, @messages)
freeze
end
attr_reader :receiver
def actor(thread)
Actor.new(thread, self)
end
def sender(thread)
Sender.new(thread, @mutex, @messages)
end
end # Mailbox
class Receiver
include Concord.new(:mutex, :mailbox)
def call
2.times do
message = try_blocking_receive
return message unless message.equal?(Undefined)
end
fail ProtocolError
end
private
def try_blocking_receive
mutex.lock
if mailbox.empty?
mutex.unlock
Thread.stop
Undefined
else
mailbox.shift.tap do
mutex.unlock
end
end
end
end # Receiver
class Sender
include Concord.new(:thread, :mutex, :mailbox)
def call(message)
mutex.synchronize do
mailbox << message
thread.run
end
self
end
end # Sender
end # Actor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment