CL-Marshal
Simple and fast marshalling of all kinds of Lisp data structures. Convert any object into a s-expression, put it on a stream an revive it from there. Only minimal changes required to make your CLOS objects serializable. Actually you only need to add 1 method per baseclass.
Homepage: https://github.com/wlbr/cl-marshal
Dependencies: none (except asdf)
License: MIT
Project is listed in Cliki.net: https://www.cliki.net/cl-marshal
Examples
Serialization of simple data
$ (ms:marshal (list 1 2 3 "Foo" "Bar" (make-array '(3) :initial-contents '(a b c))))
--> (:PCODE 1
(:LIST 1 1 2 3 (:SIMPLE-STRING 2 "Foo") (:SIMPLE-STRING 3 "Bar")
(:ARRAY 4 (3) T (A B C))))
Deserialization:
$ (ms:unmarshal '(:PCODE 1
(:LIST 1 1 2 3 (:SIMPLE-STRING 2 "Foo") (:SIMPLE-STRING 3 "Bar")
(:ARRAY 4 (3) T (A B C)))))
--> (1 2 3 "Foo" "Bar" #(A B C))
That means that a
(ms:unmarshal (ms:marshal myobject))
returns a deep clone of myobject.
Objects: A more complex example
(defclass ship ()
((name :initform "" :initarg :name :accessor name)
(dimensions :initform '(:width 0 :length 0) :initarg :dimensions :accessor dimensions)
(course :initform 0 :initarg :course :accessor course)
(cruise :initform 0 :initarg :cruise :accessor cruise) ; shall be transient
(dinghy :initform NIL :initarg :dinghy :accessor dinghy :initarg :dinghy)) ; another ship -> ref
(:documentation "A democlass. Some 'persistant slots', one transient.
Some numbers, string, lists and object references."))
(defparameter ark (make-instance 'ship :name "Ark" :course 360
:dimensions '(:width 30 :length 90)))
Nothing happens if we try to serialize this, as one important piece is missing:
$ (ms:marshal ark)
--> (:PCODE 1 NIL)
For your classes you need to add one special method:
ms:class-persistant-slots
There you are going to define the slots that shall be serialized, so that you can have persistant and transient slots in your class.
(defmethod ms:class-persistant-slots ((self ship))
'(name dimensions course dinghy))
Note that the slot cruise is not listed. Therefore it will not be serialized.
$ (ms:marshal ark)
--> (:PCODE 1
(:OBJECT 1 SHIP (:SIMPLE-STRING 2 "Ark") (:LIST 3 :WIDTH 30 :LENGTH 90) 360
(:LIST 4)))
Fine. Try a
(ms:unmarshal (ms:marshal ark))
and you will get a clone of the object ark. The whole thing works with arrays, hashtables, lists, classes/objects, subclasses incl. multiple inheritance, all of this nested and with circular references. See README.md for more detailed examples.