root/trunk/thirdparty/cl-store_0.8.4/plumbing.lisp

Revision 2554, 8.5 kB (checked in by ksprotte, 11 months ago)

added cl-store

  • Property svn:executable set to *
Line 
1 ;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*-
2 ;; See the file LICENCE for licence information
3
4 ;;  The framework where everything hangs together.
5 ;;
6
7 (in-package :cl-store)
8
9 (defvar *store-used-packages* nil
10   "If non-nil will serialize each used package otherwise will
11 only store the package name")
12 (defvar *nuke-existing-packages* nil
13   "Whether or not to overwrite existing packages on restoration.")
14 (defvar *nuke-existing-classes* nil
15   "Do we overwrite existing class definitions on restoration.")
16 (defvar *store-class-superclasses* nil
17   "Whether or not to store the superclasses of a stored class.")
18 (defvar *store-class-slots* t
19   "Whether or not to serialize slots which are class allocated.")
20
21 (declaim (type backend *default-backend* *current-backend*))
22 (defvar *default-backend*)
23 (defvar *current-backend*)
24
25
26 ;; conditions
27 ;; From 0.2.3 all conditions which are signalled from
28 ;; store or restore will signal a store-error or a
29 ;; restore-error respectively inside a handler-bind.
30 (defun cl-store-report (condition stream)
31   (declare (stream stream))
32   (aif (caused-by condition)
33        (format stream "~A" it)
34        (apply #'format stream (format-string condition)
35               (format-args condition))))
36
37 (define-condition cl-store-error (error)
38   ((caused-by :accessor caused-by :initarg :caused-by
39               :initform nil)
40    (format-string :accessor format-string :initarg :format-string
41                   :initform "Unknown")
42    (format-args :accessor format-args :initarg :format-args :initform nil))
43   (:report cl-store-report)
44   (:documentation "Root cl-store condition"))
45
46 (define-condition store-error (cl-store-error)
47   ()
48   (:documentation "Error thrown when storing an object fails."))
49
50 (define-condition restore-error (cl-store-error)
51   ()
52   (:documentation "Error thrown when restoring an object fails."))
53
54 (defun store-error (format-string &rest args)
55   (error 'store-error :format-string format-string :format-args args))
56
57 (defun restore-error (format-string &rest args)
58   (error 'restore-error :format-string format-string :format-args args))
59
60
61 ;; entry points
62 (defun store-to-file (obj place backend)
63   (declare (type backend backend)
64            (optimize speed))
65   (let ((element-type (stream-type backend)))
66     (with-open-file (s place :element-type element-type
67                        :direction :output :if-exists :supersede)
68       (backend-store backend s obj))))
69
70 (defgeneric store (obj place &optional designator)
71   (:documentation "Store OBJ into Stream PLACE using backend BACKEND.")
72   (:method ((obj t) (place t) &optional (designator *default-backend*))
73    "Store OBJ into Stream PLACE using backend BACKEND."
74    (declare (optimize speed))
75    (let* ((backend (backend-designator->backend designator))
76           (*current-backend* backend)
77           (*read-eval* nil))
78      (handler-bind ((error (lambda (c)
79                              (signal 'store-error :caused-by c))))
80        (backend-store backend place obj)))))
81
82
83 (defgeneric backend-store (backend place obj)
84   (:method ((backend backend) (place stream) (obj t))
85     "The default. Checks the streams element-type, stores the backend code
86      and calls store-object."
87     (declare (optimize speed))
88     (store-backend-code backend place)
89     (store-object obj place backend)
90     obj)
91   (:method ((backend backend) (place string) (obj t))
92     "Store OBJ into file designator PLACE."
93     (store-to-file obj place backend))
94   (:method ((backend backend) (place pathname) (obj t))
95     "Store OBJ into file designator PLACE."
96     (store-to-file obj place backend))
97   (:documentation "Method wrapped by store, override this method for
98     custom behaviour (see circularities.lisp)."))
99
100 (defgeneric store-backend-code (backend stream)
101   (:method ((backend backend) (stream t))
102     (declare (optimize speed))
103     (when-let (magic (magic-number backend))
104       (store-32-bit magic stream)))
105   (:documentation
106    "Store magic-number of BACKEND, when present, into STREAM."))
107
108 (defun store-object (obj stream &optional (backend *current-backend*))
109   "Store OBJ into STREAM. Not meant to be overridden,
110    use backend-store-object instead"
111   (backend-store-object backend obj stream))
112
113 (defgeneric backend-store-object (backend obj stream)
114   (:documentation
115    "Wrapped by store-object, override this to do custom storing
116    (see circularities.lisp for an example).")
117   (:method ((backend backend) (obj t) (stream t))
118     "The default, just calls internal-store-object."
119     (declare (optimize speed))
120     (internal-store-object backend obj stream)))
121
122
123 (defgeneric internal-store-object (backend obj place)
124   (:documentation "Method which is specialized by defstore-? macros.")
125   (:method ((backend backend) (obj t) (place t))
126     "If call falls back here then OBJ cannot be serialized with BACKEND."
127     (store-error "Cannot store objects of type ~A with backend ~(~A~)."
128                  (type-of obj) (name backend))))
129
130 ;; restoration
131 (defgeneric restore (place &optional backend)
132   (:documentation
133    "Restore and object FROM PLACE using BACKEND. Not meant to be
134    overridden, use backend-restore instead")
135   (:method (place &optional (designator *default-backend*))
136     "Entry point for restoring objects (setfable)."
137     (declare (optimize speed))
138     (let* ((backend (backend-designator->backend designator))
139            (*current-backend* backend)
140            (*read-eval* nil))
141       (handler-bind ((error (lambda (c)
142                               (signal 'restore-error :caused-by c))))
143         (backend-restore backend place)))))
144
145  
146 (defgeneric backend-restore (backend place)
147   (:documentation "Wrapped by restore. Override this to do custom restoration")
148   (:method ((backend backend) (place stream))
149     "Restore the object found in stream PLACE using backend BACKEND.
150      Checks the magic-number and invokes backend-restore-object"
151     (declare (optimize speed))
152     (check-magic-number backend place)
153     (backend-restore-object backend place))
154   (:method ((backend backend) (place string))
155     "Restore the object found in file designator PLACE using backend BACKEND."
156     (restore-from-file place backend))
157   (:method ((backend backend) (place pathname))
158     "Restore the object found in file designator PLACE using backend BACKEND."
159     (restore-from-file place backend)))
160
161 (defun restore-from-file (place backend)
162   (declare (optimize speed))
163   (let ((element-type (stream-type backend)))
164     (with-open-file (s place :element-type element-type :direction :input)
165       (backend-restore backend s))))
166      
167 (defun (setf restore) (new-val place &optional (backend *default-backend*))
168   (store new-val place backend))
169
170 (defgeneric check-magic-number (backend stream)
171   (:method ((backend backend) (stream t))
172     (let ((magic-number (magic-number backend)))
173       (declare (type (or null ub32) magic-number))
174       (when magic-number
175         (let ((val (read-32-bit stream nil)))
176           (declare (type ub32 val))
177           (cond ((= val magic-number) nil)
178                 ((member val (compatible-magic-numbers backend))
179                  nil)
180                 ((member val (old-magic-numbers backend))
181                  (restore-error "Stream contains an object stored with an ~
182 incompatible version of backend ~A." (name backend)))
183                 (t (restore-error "Stream does not contain a stored object~
184  for backend ~A."
185                                   (name backend))))))))
186   (:documentation   
187    "Check to see if STREAM actually contains a stored object for BACKEND."))
188
189 (defun lookup-reader (val readers)
190   (gethash val readers))
191
192 (defgeneric get-next-reader (backend place)
193   (:documentation
194    "Method which must be specialized for BACKEND to return
195    the next function to restore an object from PLACE.
196    If no reader is found return a second value which will be included
197    in the error.")
198   (:method ((backend backend) (place t))
199    (declare (ignore place))
200     "The default, throw an error."
201     (restore-error "get-next-reader must be specialized for backend ~(~A~)."
202                    (name backend))))
203
204 ;; Wrapper for backend-restore-object so we don't have to pass
205 ;; a backend object around all the time
206
207 (eval-when (:compile-toplevel :load-toplevel :execute)
208   (defun restore-object (place &optional (backend *current-backend*))
209     "Restore the object in PLACE using BACKEND"
210     (backend-restore-object backend place)))
211
212 (defgeneric backend-restore-object (backend place)
213   (:documentation
214    "Find the next function to call with BACKEND and invoke it with PLACE.")
215   (:method ((backend backend) (place t))
216     "The default"
217     (internal-restore-object backend (get-next-reader backend place) place)))
218
219 (defgeneric internal-restore-object (backend type place))
220
221
222 ;; EOF
Note: See TracBrowser for help on using the browser.