Files
@ 443938b472d4
Branch filter:
Location: workgroups2/workgroups-pickel.el
443938b472d4
12.0 KiB
text/x-elisp
initial commit
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 | ;;; workgroups-pickel.el --- Elisp object serdes used by Workgroups
;;
;; Copyright (C) 2010, 2011 tlh
;;
;; Author: tlh <thunkout at gmail dot com>
;; Keywords: serialization deserialization serdes
;; Homepage: https://github.com/tlh/workgroups.el
;; Version 1.0.0
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2 of the License, or (at
;; your option) any later version.
;; This program is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;; General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program; if not, write to the Free Software
;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
;; USA
;;; Commentary:
;;
;;; Code:
;;(require 'cl)
(require 'dflet)
(require 'workgroups-compat)
(require 'workgroups-utils-basic)
;;; vars
(defvar wg-pickel-identifier '~pickel!~
"Symbol identifying a stream as a pickel.")
(defvar wg-pickel-pickelable-types
'(integer float symbol string cons vector hash-table)
"Types pickel can serialize.")
(defvar wg-pickel-object-serializers
'((integer . identity)
(float . identity)
(string . identity)
(symbol . wg-pickel-symbol-serializer)
(cons . wg-pickel-cons-serializer)
(vector . wg-pickel-vector-serializer)
(hash-table . wg-pickel-hash-table-serializer))
"Alist mapping types to object serialization functions.")
(defvar wg-pickel-link-serializers
'((cons . wg-pickel-cons-link-serializer)
(vector . wg-pickel-vector-link-serializer)
(hash-table . wg-pickel-hash-table-link-serializer))
"Alist mapping types to link serialization functions.")
(defvar wg-pickel-object-deserializers
'((s . wg-pickel-deserialize-uninterned-symbol)
(c . wg-pickel-deserialize-cons)
(v . wg-pickel-deserialize-vector)
(h . wg-pickel-deserialize-hash-table))
"Alist mapping type keys to object deserialization functions.")
(defvar wg-pickel-link-deserializers
`((c . wg-pickel-cons-link-deserializer)
(v . wg-pickel-vector-link-deserializer)
(h . wg-pickel-hash-table-link-deserializer))
"Alist mapping type keys to link deserialization functions.")
;;; errors and predicates
(put 'wg-pickel-unpickelable-type-error
'error-conditions
'(error wg-pickel-errors wg-pickel-unpickelable-type-error))
(put 'wg-pickel-unpickelable-type-error
'error-message
"Attemp to pickel unpickelable type")
(defun wg-pickelable-or-error (obj)
"Error when OBJ isn't pickelable."
(unless (memq (type-of obj) wg-pickel-pickelable-types)
(signal 'wg-pickel-unpickelable-type-error
(format "Can't pickel objects of type: %S" (type-of obj))))
(typecase obj
(cons
(wg-pickelable-or-error (car obj))
(wg-pickelable-or-error (cdr obj)))
(vector
(map nil 'wg-pickelable-or-error obj))
(hash-table
(wg-dohash (key value obj)
(wg-pickelable-or-error key)
(wg-pickelable-or-error value)))))
(defun wg-pickelable-p (obj)
(condition-case err
(progn (wg-pickelable-or-error obj) t)
(wg-pickel-unpickelable-type-error nil)))
(defun wg-pickel-p (obj)
"Return t when OBJ is a pickel, nil otherwise."
(and (consp obj) (eq (car obj) wg-pickel-identifier)))
;; accessor functions
(defun wg-pickel-object-serializer (obj)
"Return the object serializer for the `type-of' OBJ."
(or (wg-aget wg-pickel-object-serializers (type-of obj))
(error "Invalid type: %S" (type-of obj))))
(defun wg-pickel-link-serializer (obj)
"Return the link serializer for the `type-of' OBJ."
(wg-aget wg-pickel-link-serializers (type-of obj)))
(defun wg-pickel-object-deserializer (key)
"Return the object deserializer for type key KEY, or error."
(or (wg-aget wg-pickel-object-deserializers key)
(error "Invalid object deserializer key: %S" key)))
(defun wg-pickel-link-deserializer (key)
"Return the link deserializer for type key KEY, or error."
(or (wg-aget wg-pickel-link-deserializers key)
(error "Invalid link deserializer key: %S" key)))
;;; bindings
(defun wg-pickel-make-bindings-table (obj)
"Return a table binding unique subobjects of OBJ to ids."
(let ((binds (make-hash-table :test 'eq))
(id -1))
;;(flet
(dflet
((inner (obj)
(unless (gethash obj binds)
(puthash obj (incf id) binds)
(case (type-of obj)
(cons
(inner (car obj))
(inner (cdr obj)))
(vector
(dotimes (idx (length obj))
(inner (aref obj idx))))
(hash-table
(wg-dohash (key val obj)
(inner key)
(inner val)))))))
(inner obj)
binds)))
;;; object serialization
(defun wg-pickel-symbol-serializer (symbol)
"Return SYMBOL's serialization."
(cond ((eq symbol t) t)
((eq symbol nil) nil)
((intern-soft symbol) symbol)
(t (list 's (symbol-name symbol)))))
(defun wg-pickel-cons-serializer (cons)
"Return CONS's serialization."
(list 'c))
(defun wg-pickel-vector-serializer (vector)
"Return VECTOR's serialization."
(list 'v (length vector)))
(defun wg-pickel-hash-table-serializer (table)
"Return HASH-TABLE's serialization."
(list 'h
(hash-table-test table)
(hash-table-size table)
(hash-table-rehash-size table)
(hash-table-rehash-threshold table)
(hash-table-weakness table)))
(defun wg-pickel-serialize-objects (binds)
"Return a list of serializations of the objects in BINDS."
(let (result)
(wg-dohash (obj id binds result)
(setq result
(nconc (list id (funcall (wg-pickel-object-serializer obj) obj))
result)))))
;;; link serialization
(defun wg-pickel-cons-link-serializer (cons binds)
"Return the serialization of CONS's links in BINDS."
(list 'c
(gethash cons binds)
(gethash (car cons) binds)
(gethash (cdr cons) binds)))
(defun wg-pickel-vector-link-serializer (vector binds)
"Return the serialization of VECTOR's links in BINDS."
(let (result)
(dotimes (i (length vector) result)
(setq result
(nconc (list 'v
(gethash vector binds)
i
(gethash (aref vector i) binds))
result)))))
(defun wg-pickel-hash-table-link-serializer (table binds)
"Return the serialization of TABLE's links in BINDS."
(let (result)
(wg-dohash (key value table result)
(setq result
(nconc (list 'h
(gethash key binds)
(gethash value binds)
(gethash table binds))
result)))))
(defun wg-pickel-serialize-links (binds)
"Return a list of serializations of the links between objects in BINDS."
(let (result)
(wg-dohash (obj id binds result)
(wg-awhen (wg-pickel-link-serializer obj)
(setq result (nconc (funcall it obj binds) result))))))
;;; object deserialization
(defun wg-pickel-deserialize-uninterned-symbol (name)
"Return a new uninterned symbol from NAME."
(make-symbol name))
(defun wg-pickel-deserialize-cons ()
"Return a new cons cell initialized to nil."
(cons nil nil))
(defun wg-pickel-deserialize-vector (length)
"Return a new vector of length LENGTH."
(make-vector length nil))
(defun wg-pickel-deserialize-hash-table (test size rsize rthresh weakness)
"Return a new hash-table with the specified properties."
(make-hash-table :test test :size size :rehash-size rsize
:rehash-threshold rthresh :weakness weakness))
(defun wg-pickel-deserialize-objects (serial-objects)
"Return a hash-table of objects deserialized from SERIAL-OBJECTS."
(let ((binds (make-hash-table)))
(wg-destructuring-dolist ((id obj . rest) serial-objects binds)
(puthash id
(if (atom obj) obj
(wg-dbind (key . data) obj
(apply (wg-pickel-object-deserializer key) data)))
binds))))
;;; link deserialization
(defun wg-pickel-cons-link-deserializer (cons-id car-id cdr-id binds)
"Relink a cons cell with its car and cdr in BINDS."
(let ((cons (gethash cons-id binds)))
(setcar cons (gethash car-id binds))
(setcdr cons (gethash cdr-id binds))))
(defun wg-pickel-vector-link-deserializer (vector-id index value-id binds)
"Relink a vector with its elements in BINDS."
(aset (gethash vector-id binds) index (gethash value-id binds)))
(defun wg-pickel-hash-table-link-deserializer (key-id value-id table-id binds)
"Relink a hash-table with its keys and values in BINDS."
(puthash (gethash key-id binds)
(gethash value-id binds)
(gethash table-id binds)))
(defun wg-pickel-deserialize-links (serial-links binds)
"Return BINDS after relinking all its objects according to SERIAL-LINKS."
(wg-destructuring-dolist ((key arg1 arg2 arg3 . rest) serial-links binds)
(funcall (wg-pickel-link-deserializer key) arg1 arg2 arg3 binds)))
;;; pickeling
(defun wg-pickel (obj)
"Return the serialization of OBJ."
(wg-pickelable-or-error obj)
(let ((binds (wg-pickel-make-bindings-table obj)))
(list wg-pickel-identifier
(wg-pickel-serialize-objects binds)
(wg-pickel-serialize-links binds)
(gethash obj binds))))
(defun wg-pickel-to-string (obj)
"Serialize OBJ to a string and return the string."
(format "%S" (wg-pickel obj)))
(defun wg-pickel-to-file (file obj)
"Serialize OBJ to FILE."
(wg-write-sexp-to-file (wg-pickel obj) file))
;;; unpickeling
(defun wg-unpickel (pickel)
"Return the deserialization of PICKEL."
(unless (wg-pickel-p pickel)
(error "Attempt to unpickel a non-pickel."))
(wg-dbind (id serial-objects serial-links result) pickel
(gethash
result
(wg-pickel-deserialize-links
serial-links
(wg-pickel-deserialize-objects serial-objects)))))
(defun wg-unpickel-file (file)
"`unpickel' an object directly from FILE."
(wg-unpickel (wg-read-sexp-from-file file)))
(defun wg-unpickel-string (str)
"`unpickel' and object directly from STR."
(wg-unpickel (read str)))
;;; parameter pickeling
(defun wg-pickel-workgroup-parameters (workgroup)
"If WORKGROUP's parameters are non-nil, return a copy of
WORKGROUP after pickeling its parameters. Otherwise return
WORKGROUP."
(if (not (wg-workgroup-parameters workgroup)) workgroup
(let ((copy (wg-copy-workgroup workgroup)))
(wg-asetf (wg-workgroup-parameters copy) (wg-pickel it))
copy)))
(defun wg-unpickel-workgroup-parameters (workgroup)
"If WORKGROUP's parameters are non-nil, return a copy of
WORKGROUP after unpickeling its parameters. Otherwise return
WORKGROUP."
(if (not (wg-workgroup-parameters workgroup)) workgroup
(let ((copy (wg-copy-workgroup workgroup)))
(wg-asetf (wg-workgroup-parameters copy) (wg-unpickel it))
copy)))
(defun wg-pickel-all-session-parameters (session)
"Return a copy of SESSION after pickeling its
parameters and the parameters of all its workgroups."
(let ((copy (wg-copy-session session)))
(when (wg-session-parameters copy)
(wg-asetf (wg-session-parameters copy) (wg-pickel it)))
(wg-asetf (wg-session-workgroup-list copy)
(mapcar 'wg-pickel-workgroup-parameters it))
copy))
(defun wg-unpickel-session-parameters (session)
"Return a copy of SESSION after unpickeling its
parameters and the parameters of all its workgroups."
(let ((copy (wg-copy-session session)))
(when (wg-session-parameters copy)
;;(message "session")
;;(sleep-for 3)
(wg-asetf (wg-session-parameters copy) (wg-unpickel it)))
(wg-asetf (wg-session-workgroup-list copy)
(mapcar 'wg-unpickel-workgroup-parameters it))
copy))
(provide 'workgroups-pickel)
|