Hey Chris,
Came across this article from a few years back while while
looking to solve a problem of my own: how to serialize &
deserialize CL structs to & from a human-friendly format. Of
course, you can just use `prin1-to-string' but the resulting
format doesn't lend itsself to hand-editing.
Anyone know of a library that would serialize a CL struct to,
say, a property list?
--
Michael <sp1ff@runbox.com>
You can reflect cl-defstruct to convert records to plists. For instance:
(cl-defstruct poi name category latitude longitude)
(defun struct-to-plist (struct)
(cl-loop for i upfrom 1
for (slot . _) in (cdr (cl-struct-slot-info (type-of struct)))
collect (intern (concat ":" (symbol-name slot)))
collect (aref struct i)))
Then, say, convert to JSON:
(json-encode
(struct-to-plist
#s(poi "Grand Canyon" natural 36.3 -112.6)))
;; => {
;; "name": "Grand Canyon",
;; "category": "natural",
;; "latitude": 36.3,
;; "longitude": -112.6
;; }
Yes, it turned out to be much simpler than I'd expected. Went
ahead and added support for reserved slots & structs expressed as
lists & vectors:
(defun struct-to-plist2 (x &rest params)
"Serialize a CL struct X to a property list.
The type of X is assumed to be in the first slot; if that is not
so, pass the :type keyword parameter with either an integer
giving the slot in which the type resides, or a symbol naming the
type of X.
By default, the resulting plist will just contain the state
necessary to deserialize X; the reader will have to \"just know\"
the type of X on read. To tag the plist with the type, pass the
keyword argument :type-tag with a non-nil value. In this case,
the plist will contain a property named :_type whose value will
be the structure name.
If the struct reserved slots using the :initial-offset value,
those slots will be serialized when non-nil with names of :_n
where n is the zero-baesd slot number."
(let ((plist)
(type-tag (plist-get params :type-tag))_)
(cl-loop for i upfrom 0
for (slot . _) in
(cl-struct-slot-info
(let ((ty (plist-get params :type)))
(cond
((integerp ty) (aref x ty))
((and ty (symbolp ty)) ty)
(t (aref x 0)))))
do
(let ((val (aref x i)))
(cond
((eq slot 'cl-tag-slot)
(if type-tag
(setq plist (plist-put plist :_type val))))
((eq slot 'cl-skip-slot)
(if val (setq plist (plist-put plist (intern
(format ":_%d" i)) val))))
(t
(if val (setq plist (plist-put plist (intern
(concat ":" (symbol-name slot))) val)))))))
plist))
Christopher Wellons <wellons@nullprogram.com> writes:
> You can reflect cl-defstruct to convert records to plists. For > instance:>> (cl-defstruct poi name category latitude longitude)>> (defun struct-to-plist (struct)> (cl-loop for i upfrom 1> for (slot . _) in (cdr (cl-struct-slot-info (type-of > struct)))> collect (intern (concat ":" (symbol-name slot)))> collect (aref struct i)))>> Then, say, convert to JSON:>> (json-encode> (struct-to-plist> #s(poi "Grand Canyon" natural 36.3 -112.6)))> ;; => {> ;; "name": "Grand Canyon",> ;; "category": "natural",> ;; "latitude": 36.3,> ;; "longitude": -112.6> ;; }
--
Michael <sp1ff@runbox.com>