X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;ds=sidebyside;f=serialize.lisp;h=981b87e945a26ae3539888d65a0f2c10b5ea28dd;hb=311b32fe13d672c97472a6ccb0e2f7a74c81110d;hp=e93a58757a13a703e75540c73db601b31af399e9;hpb=08a38deb4439dc9d2a2ac951e6754365ab6fdbaf;p=cl-protobufs.git diff --git a/serialize.lisp b/serialize.lisp index e93a587..981b87e 100644 --- a/serialize.lisp +++ b/serialize.lisp @@ -82,7 +82,7 @@ (declare (type fixnum index)) (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 + ;; Unpopulated slots should be "nullable" and will contain nil when empty `(if ,reader (funcall ,reader ,object) (slot-value ,object ,slot)))) @@ -104,33 +104,31 @@ type tag buffer index)))) ((keywordp type) (let ((tag (make-tag type (proto-index field)))) - (map () #'(lambda (v) - (setq index (serialize-prim v type tag buffer index))) - (read-slot object slot reader)))) + (doseq (v (read-slot object slot reader)) + (setq index (serialize-prim v type tag buffer index))))) ((typep (setq msg (and type (or (find-message trace type) - (find-enum trace type)))) + (find-enum trace type) + (find-type-alias trace type)))) 'protobuf-message) (if (eq (proto-message-type msg) :group) - (map () #'(lambda (v) - ;; To serialize a group, we encode a start tag, - ;; serialize the fields, then encode an end tag - (let ((tag1 (make-tag $wire-type-start-group (proto-index field))) - (tag2 (make-tag $wire-type-end-group (proto-index field)))) - (setq index (encode-uint32 tag1 buffer index)) - (map () (curry #'do-field v msg) - (proto-fields msg)) - (setq index (encode-uint32 tag2 buffer index)))) - (if slot (read-slot object slot reader) (list object))) - (map () #'(lambda (v) - ;; To serialize an embedded message, first say that it's - ;; a string, then encode its size, then serialize its fields - (let ((tag (make-tag $wire-type-string (proto-index field))) - (len (object-size v msg visited))) - (setq index (encode-uint32 tag buffer index)) - (setq index (encode-uint32 len buffer index))) - (map () (curry #'do-field v msg) - (proto-fields msg))) - (if slot (read-slot object slot reader) (list object))))) + (doseq (v (if slot (read-slot object slot reader) (list object))) + ;; To serialize a group, we encode a start tag, + ;; serialize the fields, then encode an end tag + (let ((tag1 (make-tag $wire-type-start-group (proto-index field))) + (tag2 (make-tag $wire-type-end-group (proto-index field)))) + (setq index (encode-uint32 tag1 buffer index)) + (dolist (f (proto-fields msg)) + (do-field v msg f)) + (setq index (encode-uint32 tag2 buffer index)))) + (doseq (v (if slot (read-slot object slot reader) (list object))) + ;; To serialize an embedded message, first say that it's + ;; a string, then encode its size, then serialize its fields + (let ((tag (make-tag $wire-type-string (proto-index field))) + (len (object-size v msg visited))) + (setq index (encode-uint32 tag buffer index)) + (setq index (encode-uint32 len buffer index))) + (dolist (f (proto-fields msg)) + (do-field v msg f))))) ((typep msg 'protobuf-enum) (let ((tag (make-tag $wire-type-varint (proto-index field)))) ;; 'proto-packed-p' of enum types returns nil, @@ -138,9 +136,20 @@ (if (proto-packed field) (setq index (serialize-packed-enum (read-slot object slot reader) (proto-values msg) tag buffer index)) - (map () #'(lambda (v) - (setq index (serialize-enum v (proto-values msg) tag buffer index))) - (read-slot object slot reader))))))) + (doseq (v (read-slot object slot reader)) + (setq index (serialize-enum v (proto-values msg) tag buffer index)))))) + ((typep msg 'protobuf-type-alias) + (let* ((type (proto-proto-type msg)) + (tag (make-tag type (proto-index field)))) + (doseq (v (read-slot object slot reader)) + (let ((v (funcall (proto-serializer msg) v))) + (setq index (serialize-prim v type tag buffer index)))))) + (t + (error 'undefined-field-type + :format-control "While serializing ~s to protobuf," + :format-arguments (list object) + :type-name (prin1-to-string type) + :field field)))) (t (cond ((eq type :bool) ;; We have to handle optional boolean fields specially @@ -160,7 +169,8 @@ (let ((tag (make-tag type (proto-index field)))) (setq index (serialize-prim v type tag buffer index)))))) ((typep (setq msg (and type (or (find-message trace type) - (find-enum trace type)))) + (find-enum trace type) + (find-type-alias trace type)))) 'protobuf-message) (let ((v (if slot (read-slot object slot reader) object))) (when v @@ -168,22 +178,36 @@ (let ((tag1 (make-tag $wire-type-start-group (proto-index field))) (tag2 (make-tag $wire-type-end-group (proto-index field)))) (setq index (encode-uint32 tag1 buffer index)) - (map () (curry #'do-field v msg) - (proto-fields msg)) + (dolist (f (proto-fields msg)) + (do-field v msg f)) (setq index (encode-uint32 tag2 buffer index))) (let ((tag (make-tag $wire-type-string (proto-index field))) (len (object-size v msg visited))) (setq index (encode-uint32 tag buffer index)) (setq index (encode-uint32 len buffer index)) - (map () (curry #'do-field v msg) - (proto-fields msg))))))) + (dolist (f (proto-fields msg)) + (do-field v msg f))))))) ((typep msg 'protobuf-enum) (let ((v (read-slot object slot reader))) (when v (let ((tag (make-tag $wire-type-varint (proto-index field)))) - (setq index (serialize-enum v (proto-values msg) tag buffer index))))))))))))) + (setq index (serialize-enum v (proto-values msg) tag buffer index)))))) + ((typep msg 'protobuf-type-alias) + (let ((v (read-slot object slot reader))) + (when v + (let* ((v (funcall (proto-serializer msg) v)) + (type (proto-proto-type msg)) + (tag (make-tag type (proto-index field)))) + (setq index (serialize-prim v type tag buffer index)))))) + (t + (error 'undefined-field-type + :format-control "While serializing ~s to protobuf," + :format-arguments (list object) + :type-name (prin1-to-string type) + :field field))))))))) (declare (dynamic-extent #'do-field)) - (map () (curry #'do-field object message) (proto-fields message)))) + (dolist (field (proto-fields message)) + (do-field object message field)))) (values buffer index))) @@ -329,7 +353,8 @@ (write-slot object slot writer (cons val (read-slot object slot reader))))))) ((typep (setq msg (and type (or (find-message trace type) - (find-enum trace type)))) + (find-enum trace type) + (find-type-alias trace type)))) 'protobuf-message) (if (eq (proto-message-type msg) :group) (let* ((etag (make-tag $wire-type-end-group fidx)) @@ -369,7 +394,20 @@ (t (pushnew field rslots) (write-slot object slot writer - (cons val (read-slot object slot reader))))))))))) + (cons val (read-slot object slot reader)))))))) + ((typep msg 'protobuf-type-alias) + (let ((type (proto-proto-type msg))) + (multiple-value-bind (val idx) + (deserialize-prim type buffer index) + (setq index idx) + (cond (vectorp + (push-slot object slot reader writer + (funcall (proto-deserializer msg) val))) + (t + (pushnew field rslots) + (write-slot object slot writer + (cons (funcall (proto-deserializer msg) val) + (read-slot object slot reader))))))))))) (t (cond ((keywordp type) (multiple-value-bind (val idx) @@ -377,7 +415,8 @@ (setq index idx) (write-slot object slot writer val))) ((typep (setq msg (and type (or (find-message trace type) - (find-enum trace type)))) + (find-enum trace type) + (find-type-alias trace type)))) 'protobuf-message) ;;--- If there's already a value in the slot, merge messages (if (eq (proto-message-type msg) :group) @@ -393,7 +432,14 @@ (multiple-value-bind (val idx) (deserialize-enum (proto-values msg) buffer index) (setq index idx) - (write-slot object slot writer val))))))))))))) + (write-slot object slot writer val))) + ((typep msg 'protobuf-type-alias) + (let ((type (proto-proto-type msg))) + (multiple-value-bind (val idx) + (deserialize-prim type buffer index) + (setq index idx) + (write-slot object slot writer + (funcall (proto-deserializer msg) val))))))))))))))) (declare (dynamic-extent #'deserialize)) (deserialize (proto-class message) message length end-tag))))) @@ -427,7 +473,7 @@ (declare (type fixnum size)) (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 + ;; Unpopulated slots should be "nullable" and will contain nil when empty `(if ,reader (funcall ,reader ,object) (slot-value ,object ,slot)))) @@ -446,36 +492,45 @@ (iincf size (packed-size (read-slot object slot reader) type tag)))) ((keywordp type) (let ((tag (make-tag type (proto-index field)))) - (map () #'(lambda (v) - (iincf size (prim-size v type tag))) - (read-slot object slot reader)))) + (doseq (v (read-slot object slot reader)) + (iincf size (prim-size v type tag))))) ((typep (setq msg (and type (or (find-message trace type) - (find-enum trace type)))) + (find-enum trace type) + (find-type-alias trace type)))) 'protobuf-message) (if (eq (proto-message-type msg) :group) - (map () #'(lambda (v) - (let ((tag1 (make-tag $wire-type-start-group (proto-index field))) - (tag2 (make-tag $wire-type-end-group (proto-index field)))) - (iincf size (length32 tag1)) - (map () (curry #'do-field v msg) - (proto-fields msg)) - (iincf size (length32 tag2)))) - (if slot (read-slot object slot reader) (list object))) - (map () #'(lambda (v) - (let ((tag (make-tag $wire-type-string (proto-index field))) - (len (object-size v msg visited))) - (iincf size (length32 tag)) - (iincf size (length32 len)) - (map () (curry #'do-field v msg) - (proto-fields msg)))) - (if slot (read-slot object slot reader) (list object))))) + (doseq (v (if slot (read-slot object slot reader) (list object))) + (let ((tag1 (make-tag $wire-type-start-group (proto-index field))) + (tag2 (make-tag $wire-type-end-group (proto-index field)))) + (iincf size (length32 tag1)) + (dolist (f (proto-fields msg)) + (do-field v msg f)) + (iincf size (length32 tag2)))) + (doseq (v (if slot (read-slot object slot reader) (list object))) + (let ((tag (make-tag $wire-type-string (proto-index field))) + (len (object-size v msg visited))) + (iincf size (length32 tag)) + (iincf size (length32 len)) + (dolist (f (proto-fields msg)) + (do-field v msg f)))))) ((typep msg 'protobuf-enum) (let ((tag (make-tag $wire-type-varint (proto-index field)))) (if (proto-packed field) (iincf size (packed-enum-size (read-slot object slot reader) type tag)) - (map () #'(lambda (v) - (iincf size (enum-size v (proto-values msg) tag))) - (read-slot object slot reader))))))) + (doseq (v (read-slot object slot reader)) + (iincf size (enum-size v (proto-values msg) tag)))))) + ((typep msg 'protobuf-type-alias) + (let* ((type (proto-proto-type msg)) + (tag (make-tag type (proto-index field)))) + (doseq (v (read-slot object slot reader)) + (let ((v (funcall (proto-serializer msg) v))) + (iincf size (prim-size v type tag)))))) + (t + (error 'undefined-field-type + :format-control "While computing the size of ~s in bytes," + :format-arguments (list object) + :type-name (prin1-to-string type) + :field field)))) (t (cond ((eq type :bool) (let ((v (cond ((or (eq (proto-required field) :required) @@ -493,7 +548,8 @@ (let ((tag (make-tag type (proto-index field)))) (iincf size (prim-size v type tag)))))) ((typep (setq msg (and type (or (find-message trace type) - (find-enum trace type)))) + (find-enum trace type) + (find-type-alias trace type)))) 'protobuf-message) (let ((v (if slot (read-slot object slot reader) object))) (when v @@ -501,22 +557,36 @@ (let ((tag1 (make-tag $wire-type-start-group (proto-index field))) (tag2 (make-tag $wire-type-end-group (proto-index field)))) (iincf size (length32 tag1)) - (map () (curry #'do-field v msg) - (proto-fields msg)) + (dolist (f (proto-fields msg)) + (do-field v msg f)) (iincf size (length32 tag2))) (let ((tag (make-tag $wire-type-string (proto-index field))) (len (object-size v msg visited))) (iincf size (length32 tag)) (iincf size (length32 len)) - (map () (curry #'do-field v msg) - (proto-fields msg))))))) + (dolist (f (proto-fields msg)) + (do-field v msg f))))))) ((typep msg 'protobuf-enum) (let ((v (read-slot object slot reader))) (when v (let ((tag (make-tag $wire-type-varint (proto-index field)))) - (iincf size (enum-size (read-slot object slot reader) (proto-values msg) tag))))))))))))) + (iincf size (enum-size (read-slot object slot reader) (proto-values msg) tag)))))) + ((typep msg 'protobuf-type-alias) + (let ((v (read-slot object slot reader))) + (when v + (let* ((v (funcall (proto-serializer msg) v)) + (type (proto-proto-type msg)) + (tag (make-tag type (proto-index field)))) + (iincf size (prim-size v type tag)))))) + (t + (error 'undefined-field-type + :format-control "While computing the size of ~s in bytes," + :format-arguments (list object) + :type-name (prin1-to-string type) + :field field))))))))) (declare (dynamic-extent #'do-field)) - (map () (curry #'do-field object message) (proto-fields message)) + (dolist (field (proto-fields message)) + (do-field object message field)) (when visited (setf (gethash object visited) size)) ;cache the size size)))) @@ -544,7 +614,8 @@ (let* ((class (if (eq (proto-class field) 'boolean) :bool (proto-class field))) (msg (and class (not (keywordp class)) (or (find-message message class) - (find-enum message class)))) + (find-enum message class) + (find-type-alias message class)))) (reader (cond ((proto-reader field) `(,(proto-reader field) ,vobj)) ((proto-value field) @@ -552,11 +623,13 @@ (index (proto-index field))) (when reader (cond ((eq (proto-required field) :repeated) - (let ((iterator (if (vector-field-p field) 'dovector 'dolist))) + (let* ((vectorp (vector-field-p field)) + (iterator (if vectorp 'dovector 'dolist))) (cond ((and (proto-packed field) (packed-type-p class)) (collect-serializer (let ((tag (make-tag class index))) - `(setq ,vidx (serialize-packed ,reader ,class ,tag ,vbuf ,vidx))))) + `(setq ,vidx (serialize-packed ,reader ,class ,tag ,vbuf ,vidx + ,vectorp))))) ((keywordp class) (collect-serializer (let ((tag (make-tag class index))) @@ -586,17 +659,32 @@ (collect-serializer (let ((tag (make-tag $wire-type-varint index))) (if (proto-packed field) - `(setq ,vidx (serialize-packed-enum ,reader '(,@(proto-values msg)) ,tag ,vbuf ,vidx)) + `(setq ,vidx (serialize-packed-enum ,reader '(,@(proto-values msg)) ,tag ,vbuf ,vidx + ,vectorp)) `(,iterator (,vval ,reader) - (setq ,vidx (serialize-enum ,vval '(,@(proto-values msg)) ,tag ,vbuf ,vidx)))))))))) + (setq ,vidx (serialize-enum ,vval '(,@(proto-values msg)) ,tag ,vbuf ,vidx))))))) + ((typep msg 'protobuf-type-alias) + (collect-serializer + (let* ((class (proto-proto-type msg)) + (tag (make-tag class (proto-index field)))) + `(,iterator (,vval ,reader) + (let ((,vval (funcall #',(proto-serializer msg) ,vval))) + (setq ,vidx (serialize-prim ,vval ,class ,tag ,vbuf ,vidx))))))) + (t + (error 'undefined-field-type + :format-control "While generating the serialize-object method ~ + for ~s," + :format-arguments (list message) + :type-name (prin1-to-string class) + :field field))))) (t (cond ((keywordp class) (collect-serializer (let ((tag (make-tag class index))) (if (eq class :bool) (if (or (eq (proto-required field) :required) - reader) + (null (proto-value field))) `(let ((,vval ,reader)) (setq ,vidx (serialize-prim ,vval ,class ,tag ,vbuf ,vidx))) `(let ((,vval (cond ((slot-boundp ,vobj ',(proto-value field)) @@ -634,7 +722,22 @@ (let ((tag (make-tag $wire-type-varint index))) `(let ((,vval ,reader)) (when ,vval - (setq ,vidx (serialize-enum ,vval '(,@(proto-values msg)) ,tag ,vbuf ,vidx))))))))))))) + (setq ,vidx (serialize-enum ,vval '(,@(proto-values msg)) ,tag ,vbuf ,vidx))))))) + ((typep msg 'protobuf-type-alias) + (collect-serializer + (let* ((class (proto-proto-type msg)) + (tag (make-tag class (proto-index field)))) + `(let ((,vval ,reader)) + (when ,vval + (let ((,vval (funcall #',(proto-serializer msg) ,vval))) + (setq ,vidx (serialize-prim ,vval ,class ,tag ,vbuf ,vidx)))))))) + (t + (error 'undefined-field-type + :format-control "While generating the serialize-object method ~ + for ~s," + :format-arguments (list message) + :type-name (prin1-to-string class) + :field field)))))))) `(defmethod serialize-object (,vobj (,vclass (eql ,message)) ,vbuf &optional (,vidx 0) visited) (declare #.$optimize-serialization) @@ -676,7 +779,8 @@ (let* ((class (if (eq (proto-class field) 'boolean) :bool (proto-class field))) (msg (and class (not (keywordp class)) (or (find-message message class) - (find-enum message class)))) + (find-enum message class) + (find-type-alias message class)))) (index (proto-index field))) (cond ((eq (proto-required field) :repeated) (cond ((and (proto-packed field) (packed-type-p class)) @@ -733,7 +837,24 @@ (multiple-value-bind (,vval idx) (deserialize-enum '(,@(proto-values msg)) ,vbuf ,vidx) (setq ,vidx idx) - (push ,vval ,temp))))))))) + (push ,vval ,temp))))))) + ((typep msg 'protobuf-type-alias) + (let ((class (proto-proto-type msg)) + (temp (gensym (string (proto-value field))))) + (collect-rslot (list field temp)) + (collect-deserializer + `((,(make-tag class index)) + (multiple-value-bind (,vval idx) + (deserialize-prim ,class ,vbuf ,vidx) + (setq ,vidx idx) + (push (funcall #',(proto-deserializer msg) ,vval) ,temp)))))) + (t + (error 'undefined-field-type + :format-control "While generating the deserialize-object method ~ + for ~s," + :format-arguments (list message) + :type-name (prin1-to-string class) + :field field)))) (t (cond ((keywordp class) (collect-deserializer @@ -765,7 +886,23 @@ (multiple-value-bind (,vval idx) (deserialize-enum '(,@(proto-values msg)) ,vbuf ,vidx) (setq ,vidx idx) - ,(write-slot vobj field vval))))))))))) + ,(write-slot vobj field vval))))) + ((typep msg 'protobuf-type-alias) + (let ((class (proto-proto-type msg))) + (collect-deserializer + `((,(make-tag class index)) + (multiple-value-bind (,vval idx) + (deserialize-prim ,class ,vbuf ,vidx) + (let ((,vval (funcall #',(proto-deserializer msg) ,vval))) + (setq ,vidx idx) + ,(write-slot vobj field vval))))))) + (t + (error 'undefined-field-type + :format-control "While generating the deserialize-object method ~ + for ~s," + :format-arguments (list message) + :type-name (prin1-to-string class) + :field field)))))))) (let* ((rslots (delete-duplicates rslots :key #'first)) (rfields (mapcar #'first rslots)) (rtemps (mapcar #'second rslots))) @@ -824,7 +961,8 @@ (let* ((class (if (eq (proto-class field) 'boolean) :bool (proto-class field))) (msg (and class (not (keywordp class)) (or (find-message message class) - (find-enum message class)))) + (find-enum message class) + (find-type-alias message class)))) (reader (cond ((proto-reader field) `(,(proto-reader field) ,vobj)) ((proto-value field) @@ -832,11 +970,12 @@ (index (proto-index field))) (when reader (cond ((eq (proto-required field) :repeated) - (let ((iterator (if (vector-field-p field) 'dovector 'dolist))) + (let* ((vectorp (vector-field-p field)) + (iterator (if vectorp 'dovector 'dolist))) (cond ((and (proto-packed field) (packed-type-p class)) (collect-sizer (let ((tag (make-tag class index))) - `(iincf ,vsize (packed-size ,reader ,class ,tag))))) + `(iincf ,vsize (packed-size ,reader ,class ,tag ,vectorp))))) ((keywordp class) (collect-sizer (let ((tag (make-tag class index))) @@ -866,14 +1005,27 @@ (if (proto-packed field) `(iincf ,vsize (packed-enum-size ,reader '(,@(proto-values msg)) ,tag)) `(,iterator (,vval ,reader) - (iincf ,vsize (enum-size ,vval '(,@(proto-values msg)) ,tag)))))))))) + (iincf ,vsize (enum-size ,vval '(,@(proto-values msg)) ,tag))))))) + ((typep msg 'protobuf-type-alias) + (collect-sizer + (let* ((class (proto-proto-type msg)) + (tag (make-tag class index))) + `(,iterator (,vval ,reader) + (let ((,vval (funcall #',(proto-serializer msg) ,vval))) + (iincf ,vsize (prim-size ,vval ,class ,tag))))))) + (t + (error 'undefined-field-type + :format-control "While generating the object-size method for ~s," + :format-arguments (list message) + :type-name (prin1-to-string class) + :field field))))) (t (cond ((keywordp class) (let ((tag (make-tag class index))) (collect-sizer (if (eq class :bool) (if (or (eq (proto-required field) :required) - reader) + (null (proto-value field))) `(let ((,vval ,reader)) (declare (ignorable ,vval)) (iincf ,vsize (prim-size ,vval ,class ,tag))) @@ -910,7 +1062,22 @@ (collect-sizer `(let ((,vval ,reader)) (when ,vval - (iincf ,vsize (enum-size ,vval '(,@(proto-values msg)) ,tag))))))))))))) + (iincf ,vsize (enum-size ,vval '(,@(proto-values msg)) ,tag))))))) + ((typep msg 'protobuf-type-alias) + (collect-sizer + (let* ((class (proto-proto-type msg)) + (tag (make-tag class index))) + `(let ((,vval ,reader)) + (when ,vval + (iincf ,vsize (prim-size + (funcall #',(proto-serializer msg) ,vval) + ,class ,tag))))))) + (t + (error 'undefined-field-type + :format-control "While generating the object-size method for ~s," + :format-arguments (list message) + :type-name (prin1-to-string class) + :field field)))))))) `(defmethod object-size (,vobj (,vclass (eql ,message)) &optional visited) (declare #.$optimize-serialization)