]> asedeno.scripts.mit.edu Git - cl-protobufs.git/commitdiff
Signal 'serialization-error' if there are any hard errors while (de)serializing
authorScott McKay <swmckay@gmail.com>
Sat, 6 Apr 2013 07:13:40 +0000 (12:43 +0530)
committerScott McKay <swmckay@gmail.com>
Sat, 6 Apr 2013 07:13:40 +0000 (12:43 +0530)
api.lisp
conditions.lisp
pkgdcl.lisp
serialize.lisp
text-format.lisp
wire-format.lisp

index e2743be1ae19e28b9472263f3d69b1e245dd7997..8fb8ac44000289161e7203898a16e7056269e907 100644 (file)
--- a/api.lisp
+++ b/api.lisp
@@ -19,8 +19,8 @@
 
 (defmethod object-initialized-p (object (type symbol))
   (let ((message (find-message-for-class type)))
-    (assert message ()
-            "There is no Protobuf message having the type ~S" type)
+    (unless message
+      (serialization-error "There is no Protobuf message having the type ~S" type))
     (object-initialized-p object message)))
 
 (defmethod object-initialized-p (object (message protobuf-message))
@@ -77,8 +77,8 @@
 
 (defmethod slot-initialized-p (object (type symbol) slot)
   (let ((message (find-message-for-class type)))
-    (assert message ()
-            "There is no Protobuf message having the type ~S" type)
+    (unless message
+      (serialization-error "There is no Protobuf message having the type ~S" type))
     (slot-initialized-p object message slot)))
 
 (defmethod slot-initialized-p (object (message protobuf-message) slot)
 
 (defmethod reinitialize-object (object (type symbol))
   (let ((message (find-message-for-class type)))
-    (assert message ()
-            "There is no Protobuf message having the type ~S" type)
+    (unless message
+      (serialization-error "There is no Protobuf message having the type ~S" type))
     (reinitialize-object object message)))
 
 (defmethod reinitialize-object (object (message protobuf-message))
   (:method ((object standard-object))
     (let* ((class   (type-of object))
            (message (find-message-for-class class)))
-      (assert message ()
-              "There is no Protobufs message for the class ~S" class)
+      (unless message
+        (serialization-error "There is no Protobufs message for the class ~S" class))
       (object-initialized-p object message))))
 
 (defgeneric clear (object)
   (:method ((object standard-object))
     (let* ((class   (type-of object))
            (message (find-message-for-class class)))
-      (assert message ()
-              "There is no Protobufs message for the class ~S" class)
+      (unless message
+        (serialization-error "There is no Protobufs message for the class ~S" class))
       (reinitialize-object object message))))
 
 (defgeneric has-field (object slot)
   (:method ((object standard-object) slot)
     (let* ((class   (type-of object))
            (message (find-message-for-class class)))
-      (assert message ()
-              "There is no Protobufs message for the class ~S" class)
+      (unless message
+        (serialization-error "There is no Protobufs message for the class ~S" class))
       (slot-initialized-p object message slot))))
 
 (defgeneric clear-field (object slot)
   (:method ((object standard-object) slot)
     (let* ((class   (type-of object))
            (message (find-message-for-class class)))
-      (assert message ()
-              "There is no Protobufs message for the class ~S" class)
+      (unless message
+        (serialization-error "There is no Protobufs message for the class ~S" class))
       (reinitialize-slot object message slot))))
 
 ;; This is simpler than 'object-size', but doesn't fully support aliasing
     (let* ((class   (type-of object))
            (message (find-message-for-class class))
            (type    (and message (proto-class message))))
-      (assert message ()
-              "There is no Protobufs message for the class ~S" class)
+      (unless message
+        (serialization-error "There is no Protobufs message for the class ~S" class))
       (let ((visited (make-size-cache object type)))
         (object-size object type visited)))))
 
     (let* ((class   (type-of object))
            (message (find-message-for-class class))
            (type    (and message (proto-class message))))
-      (assert message ()
-              "There is no Protobufs message for the class ~S" class)
+      (unless message
+        (serialization-error "There is no Protobufs message for the class ~S" class))
       (let* ((visited (make-size-cache object type))
              (size    (object-size object type visited))
              (start   (or start 0))
              (buffer  (or buffer (make-byte-vector size))))
-        (assert (>= (length buffer) size) ()
-                "The buffer ~S is not large enough to hold ~S" buffer object)
+        (unless (>= (length buffer) size)
+          (serialization-error "The buffer ~S is not large enough to hold ~S" buffer))
         (multiple-value-bind (nbuf nend)
             (serialize-object object type buffer start visited)
-        (declare (ignore nbuf))
-        (values nend buffer))))))
+          (declare (ignore nbuf))
+          (values nend buffer))))))
 
 (defgeneric merge-from-array (object buffer &optional start end)
   (:documentation
     (let* ((class   (type-of object))
            (message (find-message-for-class class))
            (type    (and message (proto-class message))))
-      (assert message ()
-              "There is no Protobufs message for the class ~S" class)
+      (unless message
+        (serialization-error "There is no Protobufs message for the class ~S" class))
       (let* ((start  (or start 0))
              (end    (or end (length buffer))))
         (merge-from-message object (deserialize-object type buffer start end))))))
     (let* ((class   (type-of object))
            (message (find-message-for-class class))
            (type    (and message (proto-class message))))
-      (assert message ()
-              "There is no Protobufs message for the class ~S" class)
-      (assert (eq class (type-of source)) ()
-              "The objects ~S and ~S are of not of the same class" object source)
+      (unless message
+        (serialization-error "There is no Protobufs message for the class ~S" class))
+      (unless (eq class (type-of source))
+        (serialization-error "The objects ~S and ~S are of not of the same class" object source))
       ;;--- Do this (should return side-effected 'object', not 'source')
       type
       source)))
index 5ea0b970344b861bdc9118ae07ebd3fb352f4153..8361229713930e885ce3d5a972e0ffd27340592c 100644 (file)
 (define-condition undefined-stream-type (undefined-method-type)
   ()
   (:default-initargs :where "Stream"))
+
+
+;;; (De)serialization errors
+
+(define-condition serialization-error (simple-error)
+  ()
+  (:documentation "Indicates that some sort of (de)serialization error has occurred.")
+  (:default-initargs :format-control "Serialization error")
+  (:report (lambda (condition stream)
+             (format stream "~?"
+                     (simple-condition-format-control condition)
+                     (simple-condition-format-arguments condition)))))
+
+(defun serialization-error (format-control &rest format-args)
+  (error 'serialization-error
+    :format-control format-control
+    :format-arguments (copy-list format-args)))
index bbdceee8670845359bc10585d9fda989f473a280..130d0ca43d020f01289f61d8f85a06ef4152f552 100644 (file)
@@ -56,6 +56,7 @@
    "ERROR-TYPE-NAME"
    "ERROR-FIELD"
    "ERROR-METHOD"
+   "SERIALIZATION-ERROR"
 
    ;; Object lookup
    "FIND-MESSAGE"
index 8c8f2cda8cfe9dee138a896bbfce6b26926a8a77..6160eada058dd65c011d80e399f3089be3814161 100644 (file)
@@ -65,8 +65,8 @@
 
 (defmethod clear-size-cache ((object base-protobuf-message) type)
   (let ((message (find-message-for-class type)))
-    (assert message ()
-            "There is no Protobuf message having the type ~S" type)
+    (unless message
+      (serialization-error "There is no Protobuf message having the type ~S" type))
     (macrolet ((read-slot (object slot reader)
                  `(if ,reader
                     (funcall ,reader ,object)
 
 (defmethod serialize-object (object type buffer &optional start visited)
   (let ((message (find-message-for-class type)))
-    (assert message ()
-            "There is no Protobuf message having the type ~S" type)
-    (serialize-object object message buffer start visited)))
+    (unless message
+      (serialization-error "There is no Protobuf message having the type ~S" type))
+    (handler-case        
+       (serialize-object object message buffer start visited)
+     (error (e)
+      (serialization-error "Error serializing object ~S: ~A" object (princ-to-string e))))))
 
 ;; 'visited' is used to cache object sizes
 ;; If it's non-nil. it must to be a table with the sizes already in it
 
 (defmethod deserialize-object (type buffer &optional start end (end-tag 0))
   (let ((message (find-message-for-class type)))
-    (assert message ()
-            "There is no Protobuf message having the type ~S" type)
-    (deserialize-object message buffer start end end-tag)))
+    (unless message
+      (serialization-error "There is no Protobuf message having the type ~S" type))
+    (handler-case        
+       (deserialize-object message buffer start end end-tag)
+     (error (e)
+      (serialization-error "Error deserializing buffer ~S: ~A" buffer (princ-to-string e))))))
 
 ;; The default method uses metadata from the protobuf "schema" for the message
 (defmethod deserialize-object ((message protobuf-message) buffer &optional start end (end-tag 0))
                            ;; If there's no field descriptor for this index, just skip
                            ;; the next element in the buffer having the given wire type
                            (setq index (skip-element buffer index tag))
-                           ;;--- Check for mismatched wire type, running past end of buffer, etc
+                           ;; We don't explicitly check for mismatched wire type, running past the
+                           ;; end of the buffer, etc; instead, we'll count on the high likelihood
+                           ;; of some kind of an error getting signalled (e.g., array out of bounds)
+                           ;; and catch it at a higher level. Yay, Lisp!
                            (cond ((and field (eq (proto-required field) :repeated))
                                   (let ((vectorp (vector-field-p field)))
                                     (cond ((and (proto-packed field) (packed-type-p type))
 
 (defmethod object-size (object type &optional visited)
   (let ((message (find-message-for-class type)))
-    (assert message ()
-            "There is no Protobuf message having the type ~S" type)
+    (unless message
+      (serialization-error "There is no Protobuf message having the type ~S" type))
     (object-size object message visited)))
 
 ;; 'visited' is used to cache object sizes
index 3b4bb5c1332c6dc974298cb0f9f8202824b512cd..b09f98844fe204314429d2e862448d985efb5e45 100644 (file)
@@ -27,8 +27,8 @@
                                    (suppress-line-breaks *suppress-line-breaks*) (print-name t))
   (let* ((type    (or type (type-of object)))
          (message (find-message-for-class type)))
-    (assert message ()
-            "There is no Protobuf message having the type ~S" type)
+    (unless message
+      (serialization-error "There is no Protobuf message having the type ~S" type))
     (macrolet ((read-slot (object slot reader)
                  ;; Don't do a boundp check, we assume the object is fully populated
                  ;; Unpopulated slots should be "nullable" and should contain nil
 (defmethod parse-text-format ((type symbol)
                               &key (stream *standard-input*) (parse-name t))
   (let ((message (find-message-for-class type)))
-    (assert message ()
-            "There is no Protobuf message having the type ~S" type)
+    (unless message
+      (serialization-error "There is no Protobuf message having the type ~S" type))
     (parse-text-format message :stream stream :parse-name parse-name)))
 
 (defmethod parse-text-format ((message protobuf-message)
                               &key (stream *standard-input*) (parse-name t))
   (when parse-name
     (let ((name (parse-token stream)))
-      (assert (string= name (proto-name message)) ()
-              "The message is not of the expected type ~A" (proto-name message))))
+      (unless (string= name (proto-name message))
+        (serialization-error "The message is not of the expected type ~A" (proto-name message)))))
   (labels ((deserialize (type trace)
              (let* ((message (find-message trace type))
                     (object  (and message
index fffa360ffd0e2c130786edc108e2eddd844d49e7..b2eb45fef883b52af2986abdc8ea839a26418eac 100644 (file)
        (let ((idx (encode-uint32 ,tag ,buffer ,index)))
          (declare (type fixnum idx))
          ,(ecase type
-            ((:int32 )
+            ((:int32)
              `(encode-uint32 (ldb (byte 32 0) ,val) ,buffer idx))
             ((:int64)
              `(encode-uint64 (ldb (byte 64 0) ,val) ,buffer idx))
            (type (unsigned-byte 32) tag))
   (let ((idx (let ((e (find val enum-values :key #'proto-value)))
                (and e (proto-index e)))))
-    (assert idx () "There is no enum value for ~S" val)
+    (unless idx
+      (serialization-error "There is no enum value for ~S" val))
     (i+ (length32 tag) (length32 (ldb (byte 32 0) idx)))))
 
 (defun packed-enum-size (values enum-values tag)
                (map () #'(lambda (val)
                            (let ((idx (let ((e (find val enum-values :key #'proto-value)))
                                         (and e (proto-index e)))))
-                             (assert idx () "There is no enum value for ~S" val)
+                             (unless idx
+                               (serialization-error "There is no enum value for ~S" val))
                              (iincf len (length32 (ldb (byte 32 0) idx))))) values)
                len)))
     (declare (type (unsigned-byte 32) len))
                       (setq val (,logior val (,ash bits places))))
                  until (i< byte 128)
                  finally (progn
-                           (assert (< val ,(ash 1 bits)) ()
-                                   "The value ~D is longer than ~A bits" val ,bits)
+                           (unless (< val ,(ash 1 bits))
+                             (serialization-error "The value ~D is longer than ~A bits" val ,bits))
                            (return (values val index))))))
        (defun ,decode-int (buffer index)
          ,(format nil
                    ((i= (i- tag $wire-type-start-group) (i- new-tag $wire-type-end-group))
                     (return idx))
                    (t
-                    (assert (i= (i- tag $wire-type-start-group) (i- new-tag $wire-type-end-group)) ()
-                            "Couldn't find a matching end group tag"))))))
+                    (unless (i= (i- tag $wire-type-start-group) (i- new-tag $wire-type-end-group))
+                      (serialization-error "Couldn't find a matching end group tag")))))))
     (t index)))