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

Revision 2554, 6.8 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 ;; CL-STORE now has a concept of backends.
5 ;; store and restore now take an optional  backend as an
6 ;;  argument to do the actual restoring. Examples of use are
7 ;; in default-backend.lisp and xml-backend.lisp
8
9 (in-package :cl-store)
10
11 (defun required-arg (name)
12   (error "~S is a required argument" name))
13
14 (defclass backend ()
15   ((name :accessor name :initform "Unknown" :initarg :name :type symbol)
16    (magic-number :accessor magic-number :initarg :magic-number :type integer)
17    (compatible-magic-numbers :accessor compatible-magic-numbers
18                              :initarg :compatible-magic-numbers :type list)
19    (old-magic-numbers :accessor old-magic-numbers :initarg :old-magic-numbers
20                       :type list)
21    (stream-type :accessor stream-type :initarg :stream-type :type (or symbol cons)
22                 :initform (required-arg :stream-type)))
23   (:documentation "Core class which custom backends must extend"))
24
25 (deftype backend-designator ()
26   `(or symbol backend))
27
28 (defparameter *registered-backends* nil
29   "An assoc list mapping backend-names to the backend objects")
30
31 (defun find-backend (name &optional errorp)
32   (declare (type symbol name))
33   "Return backup called NAME. If there is no such backend NIL is returned
34 if ERRORP is false, otherwise an error is signalled."
35   (or (cdr (assoc name *registered-backends*))
36       (if errorp
37           (error "Backend named ~S does not exist." name)
38           nil)))
39
40 (defun backend-designator->backend (designator)
41   (check-type designator backend-designator)
42   (etypecase designator
43     (symbol (find-backend designator t))
44     (backend designator)))
45
46
47 #+lispworks
48 (defun get-store-macro (name)
49   "Return the defstore-? macro which will be used by a custom backend"
50   (let ((macro-name (symbolicate 'defstore- name)))
51     `(defmacro ,macro-name ((var type stream &optional qualifier)
52                             &body body)
53        (with-gensyms (gbackend)
54          `(dspec:def (,',macro-name (,var ,type ,stream))
55             (defmethod internal-store-object ,@(if qualifier (list qualifier) nil)
56               ((,gbackend ,',name) (,var ,type) ,stream)
57               ,(format nil "Definition for storing an object of type ~A with ~
58  backend ~A" type ',name)
59               (declare (ignorable ,gbackend))
60               ,@body))))))
61
62 #-lispworks
63 (defun get-store-macro (name)
64   "Return the defstore-? macro which will be used by a custom backend"
65   (let ((macro-name (symbolicate 'defstore- name)))
66     `(defmacro ,macro-name ((var type stream &optional qualifier)
67                             &body body)
68        (with-gensyms (gbackend)
69          `(defmethod internal-store-object ,@(if qualifier (list qualifier) nil)
70               ((,gbackend ,',name) (,var ,type) ,stream)
71               ,(format nil "Definition for storing an object of type ~A with ~
72  backend ~A" type ',name)
73               (declare (ignorable ,gbackend))
74               ,@body)))))
75
76 #+lispworks
77 (defun get-restore-macro (name)
78   "Return the defrestore-? macro which will be used by a custom backend"
79   (let ((macro-name (symbolicate 'defrestore- name)))
80     `(defmacro ,macro-name ((type place &optional qualifier) &body body)
81        (with-gensyms (gbackend gtype)
82          `(dspec:def (,',macro-name (,type ,place))
83             (defmethod internal-restore-object ,@(if qualifier (list qualifier) nil)
84               ((,gbackend ,',name) (,gtype (eql ',type)) (,place t))
85               (declare (ignorable ,gbackend ,gtype))
86               ,@body))))))
87
88 #-lispworks
89 (defun get-restore-macro (name)
90   "Return the defrestore-? macro which will be used by a custom backend"
91   (let ((macro-name (symbolicate 'defrestore- name)))
92     `(defmacro ,macro-name ((type place &optional qualifier) &body body)
93        (with-gensyms (gbackend gtype)
94          `(defmethod internal-restore-object ,@(if qualifier (list qualifier) nil)
95             ((,gbackend ,',name) (,gtype (eql ',type)) (,place t))
96             (declare (ignorable ,gbackend ,gtype))
97             ,@body)))))
98
99
100 (defun register-backend (name class magic-number stream-type old-magic-numbers
101                               compatible-magic-numbers)
102   (declare (type symbol name))
103   (let ((instance (make-instance class
104                                  :name name
105                                  :magic-number magic-number
106                                  :old-magic-numbers old-magic-numbers
107                                  :compatible-magic-numbers compatible-magic-numbers
108                                  :stream-type  stream-type)))
109     (if (assoc name *registered-backends*)
110         (cerror "Redefine backend" "Backend ~A is already defined." name)
111         (push (cons name instance) *registered-backends*))
112     instance))
113
114 (defun alias-backend (old alias)
115   (let ((backend (find-backend old t)))
116     (pushnew (cons alias backend) *registered-backends*
117              :test #'equalp)
118     t))
119
120 (defun get-class-form (name fields extends)
121   `(defclass ,name ,extends
122     ,fields
123     (:documentation ,(format nil "Autogenerated cl-store class for backend ~(~A~)."
124                              name))))
125
126
127 #+lispworks
128 (defun get-dspec-alias-and-parser (name)
129   (let ((store-name (symbolicate 'defstore- name))
130         (restore-name (symbolicate 'defrestore- name)))
131     `( (dspec:define-dspec-alias ,store-name (arglist)
132          `(method cl-store::internal-store-object ,arglist))
133        (dspec:define-form-parser ,store-name (arglist)
134          `(,,store-name ,arglist))
135
136        (dspec:define-dspec-alias ,restore-name (arglist)
137          `(method cl-store::internal-restore-object ,arglist))
138
139        (dspec:define-form-parser ,restore-name (arglist)
140          `(,,restore-name ,arglist)))))
141
142
143 (defmacro defbackend (name &key (stream-type ''(unsigned-byte 8))
144                            (magic-number nil) fields (extends '(backend))
145                            (old-magic-numbers nil) (compatible-magic-numbers nil))
146   "Defines a new backend called NAME. Stream type must be either 'char or 'binary.
147 FIELDS is a list of legal slots for defclass. MAGIC-NUMBER, when supplied, will
148 be written down stream as verification and checked on restoration.
149 EXTENDS is a class to extend, which must be backend or a class which extends
150 backend"
151   (assert (symbolp name))
152   `(eval-when (:load-toplevel :execute)
153      (eval-when (:compile-toplevel :load-toplevel :execute)
154        #+lispworks ,@(get-dspec-alias-and-parser name)
155        ,(get-class-form name fields extends)
156        ,(get-store-macro name)
157        ,(get-restore-macro name))
158      (register-backend ',name ',name ,magic-number
159                        ,stream-type ',old-magic-numbers ',compatible-magic-numbers)))
160
161 (defmacro with-backend (backend &body body)
162   "Run BODY with *default-backend* bound to BACKEND"
163   `(let* ((*default-backend* (backend-designator->backend ,backend)))
164     ,@body))
165
166 ;; EOF
Note: See TracBrowser for help on using the browser.