cl-scopes/core/actor.lisp

94 lines
2.4 KiB
Common Lisp

;;;; cl-scopes/core/actor - basic actor definitions
(defpackage :scopes/core/actor
(:use :common-lisp)
(:local-nicknames (:async :scopes/util/async)
(:util :scopes/util))
(:export #:actor #:bg-actor #:become #:create #:send
#:message #:content #:customer
#:*logger* #:*root*
#:echo #:inc #:lgi
#:calculator #:plus #:minus #:show #:send-value))
(in-package :scopes/core/actor)
;;;; basic message and actor implementations
(defclass message ()
((content :reader content :initarg :content :initform nil)
(customer :reader customer :initarg :customer :initform nil)))
(defun message (content &optional customer)
(make-instance 'message :content content :customer customer))
(defclass actor ()
((behavior :accessor behavior :initarg :behavior :initform #'no-op)))
(defclass bg-actor (actor)
((task :accessor task :initform nil)))
(defgeneric start (ac)
(:method ((ac actor)))
(:method ((ac bg-actor))
(setf (task ac)
(async:make-task
:handle-message #'(lambda (ax msg)
(funcall (behavior ac) ac msg))))
(async:start (task ac))))
(defgeneric deliver (ac msg)
(:method ((ac actor) msg)
(funcall (behavior ac) ac msg))
(:method ((ac bg-actor) msg)
(async:send (task ac) msg)))
;;;; the core (classical, i.e. Hewitt) actor API
(defun become (ac bhv)
(setf (behavior ac) bhv))
(defun create (bhv &optional (cls 'actor))
(let ((ac (make-instance cls :behavior bhv)))
(start ac)
ac))
(defun send (addr content &key customer)
(let ((ac addr) (msg (message content customer)))
(deliver ac msg)))
;;;; predefined behaviors
(defun no-op (ac msg))
(defun lgi (ac msg)
(util:lgi (content msg)))
(defun echo (ac msg)
(send (customer msg) msg))
;;;; predefined global actors
(defvar *logger* (create #'lgi))
(defclass root (actor) ())
(defun root-bhv (ac msg)
(send *logger* msg))
(defvar *root* (create #'root-bhv 'root))
;;;; example behavior: calculator
(defun calculator (&optional (val 0))
#'(lambda (ac msg)
(destructuring-bind (fn &optional param) (content msg)
(funcall fn ac msg val param))))
(defun plus (ac msg val param)
(become ac (calculator (+ val param))))
(defun minus (ac msg val param)
(become ac (calculator (- val param))))
(defun show (ac msg val param)
(send (or (customer msg) *logger*) val))
(defun send-value (ac msg val param)
(send (customer msg) val))