(defconstant $wire-type-varint 0)
(defconstant $wire-type-64bit 1)
(defconstant $wire-type-string 2)
+(defconstant $wire-type-start-group 3) ;supposedly obsolete
+(defconstant $wire-type-end-group 4) ;supposedly obsolete
(defconstant $wire-type-32bit 5)
(defun make-tag (type index)
(defun zig-zag-encode32 (val)
+ (declare (optimize (speed 3) (safety 0) (debug 0)))
(declare (type (signed-byte 32) val))
- (locally (declare (optimize (speed 3) (safety 0) (debug 0)))
- (logxor (ash val 1) (ash val -31))))
+ (logxor (ash val 1) (ash val -31)))
(defun zig-zag-encode64 (val)
+ (declare (optimize (speed 3) (safety 0) (debug 0)))
(declare (type (signed-byte 64) val))
- (locally (declare (optimize (speed 3) (safety 0) (debug 0)))
- (logxor (ash val 1) (ash val -63))))
+ (logxor (ash val 1) (ash val -63)))
(define-compiler-macro zig-zag-encode32 (&whole form val)
(if (atom val)
form))
(defun zig-zag-decode32 (val)
- (locally (declare (optimize (speed 3) (safety 0) (debug 0)))
- (logxor (ash val -1) (- (logand val 1)))))
+ (declare (optimize (speed 3) (safety 0) (debug 0)))
+ (logxor (ash val -1) (- (logand val 1))))
(defun zig-zag-decode64 (val)
- (locally (declare (optimize (speed 3) (safety 0) (debug 0)))
- (logxor (ash val -1) (- (logand val 1)))))
+ (declare (optimize (speed 3) (safety 0) (debug 0)))
+ (logxor (ash val -1) (- (logand val 1))))
(define-compiler-macro zig-zag-decode32 (&whole form val)
(if (atom val)
(defun serialize-prim (val type tag buffer index)
"Serializes a Protobufs primitive (scalar) value into the buffer at the given index.
The value is given by 'val', the primitive type by 'type'.
- Modifies the buffer in place, and returns the new index into the buffer."
+ Modifies the buffer in place, and returns the new index into the buffer.
+ Watch out, this function turns off most type checking and all array bounds checking."
(declare (type (simple-array (unsigned-byte 8)) buffer)
(type (unsigned-byte 32) tag)
(type fixnum index))
((:sfixed64)
(encode-sfixed64 val buffer idx))
((:string)
- (encode-octets (babel:string-to-octets val :encoding :utf-8) buffer idx))
+ (encode-string val buffer idx))
((:bytes)
(encode-octets val buffer idx))
((:bool)
(encode-double val buffer idx))
;; A few of our homegrown types
((:symbol)
- (let ((val (format nil "~A:~A" (package-name (symbol-package val)) (symbol-name val))))
- ;; Call 'string' in case we are trying to serialize a symbol name
- (encode-octets (babel:string-to-octets val :encoding :utf-8) buffer idx)))
+ (let ((val (if (keywordp val)
+ (string val)
+ ;; Non-keyword symbols are consy, avoid them if possible
+ (format nil "~A:~A" (package-name (symbol-package val)) (symbol-name val)))))
+ (encode-string val buffer idx)))
((:date :time :datetime :timestamp)
(encode-uint64 val buffer idx))))))
(if (member type '(:int32 :uint32 :int64 :uint64 :sint32 :sint64
:fixed32 :sfixed32 :fixed64 :sfixed64
:string :bytes :bool :float :double))
- `(locally (declare (optimize (speed 3) (safety 0) (debug 0)))
+ `(locally (declare (optimize (speed 3) (safety 0) (debug 0))
+ (type (simple-array (unsigned-byte 8)) ,buffer)
+ ;; 'tag' is a constant, no need to declare its type
+ (type fixnum ,index))
(let ((idx (encode-uint32 ,tag ,buffer ,index)))
(declare (type fixnum idx))
,(ecase type
((:sfixed64)
`(encode-sfixed64 ,val ,buffer idx))
((:string)
- `(encode-octets (babel:string-to-octets ,val :encoding :utf-8) ,buffer idx))
+ `(encode-string ,val ,buffer idx))
((:bytes)
`(encode-octets ,val ,buffer idx))
((:bool)
(defun serialize-packed (values type tag buffer index)
"Serializes a set of packed values into the buffer at the given index.
The values are given by 'values', the primitive type by 'type'.
- Modifies the buffer in place, and returns the new index into the buffer."
+ Modifies the buffer in place, and returns the new index into the buffer.
+ Watch out, this function turns off most type checking and all array bounds checking."
(declare (type (simple-array (unsigned-byte 8)) buffer)
(type (unsigned-byte 32) tag)
(type fixnum index))
(if (member type '(:int32 :uint32 :int64 :uint64 :sint32 :sint64
:fixed32 :sfixed32 :fixed64 :sfixed64
:float :double))
- `(locally (declare (optimize (speed 3) (safety 0) (debug 0)))
+ `(locally (declare (optimize (speed 3) (safety 0) (debug 0))
+ (type (simple-array (unsigned-byte 8)) ,buffer)
+ (type fixnum ,index))
(let ((idx (encode-uint32 ,tag ,buffer ,index)))
(declare (type fixnum idx))
(multiple-value-bind (full-len len)
(defun serialize-enum (val values tag buffer index)
"Serializes a Protobufs enum value into the buffer at the given index.
The value is given by 'val', the enum values are in 'values'.
- Modifies the buffer in place, and returns the new index into the buffer."
+ Modifies the buffer in place, and returns the new index into the buffer.
+ Watch out, this function turns off most type checking and all array bounds checking."
(declare (type (simple-array (unsigned-byte 8)) buffer)
(type (unsigned-byte 32) tag)
(type fixnum index))
(defun deserialize-prim (type buffer index)
"Deserializes the next object of primitive type 'type'.
Deserializes from the byte vector 'buffer' starting at 'index'.
- Returns the value and and the new index into the buffer."
+ Returns the value and and the new index into the buffer.
+ Watch out, this function turns off most type checking and all array bounds checking."
(declare (type (simple-array (unsigned-byte 8)) buffer)
(type fixnum index))
(locally (declare (optimize (speed 3) (safety 0) (debug 0)))
((:sfixed64)
(decode-sfixed64 buffer index))
((:string)
- (multiple-value-bind (val idx)
- (decode-octets buffer index)
- (values (babel:octets-to-string val :encoding :utf-8) idx)))
+ (decode-string buffer index))
((:bytes)
(decode-octets buffer index))
((:bool)
(decode-double buffer index))
;; A few of our homegrown types
((:symbol)
+ ;; Note that this is consy, avoid it if possible
(multiple-value-bind (val idx)
- (decode-octets buffer index)
- (let* ((val (babel:octets-to-string val :encoding :utf-8))
- (colon (position #\: val))
- (pkg (subseq val 0 colon))
- (sym (subseq val (i+ colon 1))))
- (values (intern sym pkg) idx))))
+ (decode-string buffer index)
+ (values (make-lisp-symbol val) idx)))
((:date :time :datetime :timestamp)
(decode-uint64 buffer index)))))
(if (member type '(:int32 :uint32 :int64 :uint64 :sint32 :sint64
:fixed32 :sfixed32 :fixed64 :sfixed64
:string :bytes :bool :float :double))
- `(locally (declare (optimize (speed 3) (safety 0) (debug 0)))
+ `(locally (declare (optimize (speed 3) (safety 0) (debug 0))
+ (type (simple-array (unsigned-byte 8)) ,buffer)
+ (type fixnum ,index))
,(ecase type
((:int32 :uint32)
`(decode-uint32 ,buffer ,index))
((:sfixed64)
`(decode-sfixed64 ,buffer ,index))
((:string)
- `(multiple-value-bind (val idx)
- (decode-octets ,buffer ,index)
- (values (babel:octets-to-string val :encoding :utf-8) idx)))
+ `(decode-string ,buffer ,index))
((:bytes)
`(decode-octets ,buffer ,index))
((:bool)
(defun deserialize-packed (type buffer index)
"Deserializes the next packed values of type 'type'.
Deserializes from the byte vector 'buffer' starting at 'index'.
- Returns the value and and the new index into the buffer."
+ Returns the value and and the new index into the buffer.
+ Watch out, this function turns off most type checking and all array bounds checking."
(declare (type (simple-array (unsigned-byte 8)) buffer)
(type fixnum index))
(locally (declare (optimize (speed 3) (safety 0) (debug 0)))
(collect-value val)
(setq idx nidx))))))))
+(define-compiler-macro deserialize-packed (&whole form type buffer index)
+ (if (member type '(:int32 :uint32 :int64 :uint64 :sint32 :sint64
+ :fixed32 :sfixed32 :fixed64 :sfixed64
+ :float :double))
+ `(locally (declare (optimize (speed 3) (safety 0) (debug 0))
+ (type (simple-array (unsigned-byte 8)) ,buffer)
+ (type fixnum ,index))
+ (multiple-value-bind (len idx)
+ (decode-uint32 .buffer ,index)
+ (declare (type (unsigned-byte 32) len)
+ (type fixnum idx))
+ (let ((end (i+ idx len)))
+ (declare (type (unsigned-byte 32) end))
+ (with-collectors ((values collect-value))
+ (loop
+ (when (>= idx end)
+ (return-from deserialize-packed (values values idx)))
+ (multiple-value-bind (val nidx)
+ ,(ecase type
+ ((:int32 :uint32)
+ `(decode-uint32 ,buffer idx))
+ ((:int64 :uint64)
+ `(decode-uint64 ,buffer idx))
+ ((:sint32)
+ `(multiple-value-bind (val idx)
+ (decode-uint32 ,buffer idx)
+ (values (zig-zag-decode32 val) idx)))
+ ((:sint64)
+ `(multiple-value-bind (val idx)
+ (decode-uint64 ,buffer idx)
+ (values (zig-zag-decode64 val) idx)))
+ ((:fixed32)
+ `(decode-fixed32 ,buffer idx))
+ ((:sfixed32)
+ `(decode-sfixed32 ,buffer idx))
+ ((:fixed64)
+ `(decode-fixed64 ,buffer idx))
+ ((:sfixed64)
+ `(decode-sfixed64 ,buffer idx))
+ ((:float)
+ `(decode-single ,buffer idx))
+ ((:double)
+ `(decode-double ,buffer idx)))
+ (collect-value val)
+ (setq idx nidx)))))))
+ form))
+
(defun deserialize-enum (values buffer index)
"Deserializes the next enum value take from 'values'.
Deserializes from the byte vector 'buffer' starting at 'index'.
- Returns the value and and the new index into the buffer."
+ Returns the value and and the new index into the buffer.
+ Watch out, this function turns off most type checking and all array bounds checking."
(declare (type (simple-array (unsigned-byte 8)) buffer)
(type fixnum index))
(locally (declare (optimize (speed 3) (safety 0) (debug 0)))
;;; Object sizing
(defun prim-size (val type tag)
- "Returns the size in bytes that the primitive object will take when serialized."
+ "Returns the size in bytes that the primitive object will take when serialized.
+ Watch out, this function turns off most type checking."
(declare (type (unsigned-byte 32) tag))
(locally (declare (optimize (speed 3) (safety 0) (debug 0)))
(ecase type
(let ((len (babel:string-size-in-octets val :encoding :utf-8)))
(i+ (length32 tag) (length32 len) len)))
((:bytes)
- (locally (declare (optimize (speed 3) (safety 0) (debug 0)))
- (let ((len (length val)))
- (i+ (length32 tag) (length32 len) len))))
+ (let ((len (length val)))
+ (i+ (length32 tag) (length32 len) len)))
((:bool)
(i+ (length32 tag) 1))
((:float)
(i+ (length32 tag) 8))
;; A few of our homegrown types
((:symbol)
- (let* ((len (i+ (length (package-name (symbol-package val))) 1 (length (symbol-name val)))))
+ (let ((len (if (keywordp val)
+ (length (symbol-name val))
+ (i+ (length (package-name (symbol-package val))) 1 (length (symbol-name val))))))
(i+ (length32 tag) (length32 len) len)))
((:date :time :datetime :timestamp)
(i+ (length32 tag) 8)))))
form))
(defun packed-size (values type tag)
- "Returns the size in bytes that the packed object will take when serialized."
+ "Returns the size in bytes that the packed object will take when serialized.
+ Watch out, this function turns off most type checking."
(declare (type (unsigned-byte 32) tag))
(locally (declare (optimize (speed 3) (safety 0) (debug 0)))
(let ((len (let ((len 0))
(if (member type '(:int32 :uint32 :int64 :uint64 :sint32 :sint64
:fixed32 :sfixed32 :fixed64 :sfixed64
:float :double))
- `(locally (declare (optimize (speed 3) (safety 0) (debug 0))
- (type (unsigned-byte 32) tag))
+ `(locally (declare (optimize (speed 3) (safety 0) (debug 0)))
(let ((len (let ((len 0))
(declare (type fixnum len))
(dolist (val ,values len)
((:float) `4)
((:double) `8)))))))
(declare (type (unsigned-byte 32) len))
- (values (i+ (length32 ,tag) (length32 len) len) len)))
+ (values (i+ (length32 (the (unsigned-byte 32) ,tag)) (length32 len) len) len)))
form))
(defun enum-size (val values tag)
"Returns the size in bytes that the enum object will take when serialized."
(declare (type (unsigned-byte 32) tag))
- (let ((val (let ((e (find val values :key #'proto-value)))
+ (let ((idx (let ((e (find val values :key #'proto-value)))
(and e (proto-index e)))))
- (declare (type (unsigned-byte 32) val))
- (i+ (length32 tag) (length32 val))))
+ (assert idx () "There is no enum value for ~S" val)
+ (i+ (length32 tag) (length32 idx))))
;;; Raw encoders
(defun encode-uint32 (val buffer index)
"Encodes the unsigned 32-bit integer 'val' as a varint into the buffer
at the given index.
- Modifies the buffer, and returns the new index into the buffer."
+ Modifies the buffer, and returns the new index into the buffer.
+ Watch out, this function turns off all type checking and array bounds checking."
+ (declare (optimize (speed 3) (safety 0) (debug 0)))
(declare (type (unsigned-byte 32) val)
(type (simple-array (unsigned-byte 8)) buffer)
(type fixnum index))
- (locally (declare (optimize (speed 3) (safety 0) (debug 0)))
- ;; Seven bits at a time, least significant bits first
- (loop do (let ((bits (ldb #.(byte 7 0) val)))
- (declare (type (unsigned-byte 8) bits))
- (setq val (ash val -7))
- (setf (aref buffer index) (ilogior bits (if (zerop val) 0 128)))
- (iincf index))
- until (zerop val)))
+ ;; Seven bits at a time, least significant bits first
+ (loop do (let ((bits (ldb (byte 7 0) val)))
+ (declare (type (unsigned-byte 8) bits))
+ (setq val (ash val -7))
+ (setf (aref buffer index) (ilogior bits (if (zerop val) 0 128)))
+ (iincf index))
+ until (zerop val))
(values index buffer)) ;return the buffer to improve 'trace'
(defun encode-uint64 (val buffer index)
"Encodes the unsigned 64-bit integer 'val' as a varint into the buffer
at the given index.
- Modifies the buffer, and returns the new index into the buffer."
+ Modifies the buffer, and returns the new index into the buffer.
+ Watch out, this function turns off all type checking and array bounds checking."
+ (declare (optimize (speed 3) (safety 0) (debug 0)))
(declare (type (unsigned-byte 64) val)
(type (simple-array (unsigned-byte 8)) buffer)
(type fixnum index))
- (locally (declare (optimize (speed 3) (safety 0) (debug 0)))
- (loop do (let ((bits (ldb #.(byte 7 0) val)))
- (declare (type (unsigned-byte 8) bits))
- (setq val (ash val -7))
- (setf (aref buffer index) (ilogior bits (if (zerop val) 0 128)))
- (iincf index))
- until (zerop val)))
+ (loop do (let ((bits (ldb (byte 7 0) val)))
+ (declare (type (unsigned-byte 8) bits))
+ (setq val (ash val -7))
+ (setf (aref buffer index) (ilogior bits (if (zerop val) 0 128)))
+ (iincf index))
+ until (zerop val))
(values index buffer))
(defun encode-fixed32 (val buffer index)
"Encodes the unsigned 32-bit integer 'val' as a fixed int into the buffer
at the given index.
- Modifies the buffer, and returns the new index into the buffer."
+ Modifies the buffer, and returns the new index into the buffer.
+ Watch out, this function turns off most type checking and all array bounds checking."
(declare (type (unsigned-byte 32) val)
(type (simple-array (unsigned-byte 8)) buffer)
(type fixnum index))
(locally (declare (optimize (speed 3) (safety 0) (debug 0)))
(loop repeat 4 doing
- (let ((byte (ldb #.(byte 8 0) val)))
+ (let ((byte (ldb (byte 8 0) val)))
(declare (type (unsigned-byte 8) byte))
(setq val (ash val -8))
(setf (aref buffer index) byte)
(defun encode-fixed64 (val buffer index)
"Encodes the unsigned 64-bit integer 'val' as a fixed int into the buffer
at the given index.
- Modifies the buffer, and returns the new index into the buffer."
+ Modifies the buffer, and returns the new index into the buffer.
+ Watch out, this function turns off most type checking and all array bounds checking."
(declare (type (unsigned-byte 64) val)
(type (simple-array (unsigned-byte 8)) buffer)
(type fixnum index))
(locally (declare (optimize (speed 3) (safety 0) (debug 0)))
(loop repeat 8 doing
- (let ((byte (ldb #.(byte 8 0) val)))
+ (let ((byte (ldb (byte 8 0) val)))
(declare (type (unsigned-byte 8) byte))
(setq val (ash val -8))
(setf (aref buffer index) byte)
(defun encode-sfixed32 (val buffer index)
"Encodes the signed 32-bit integer 'val' as a fixed int into the buffer
at the given index.
- Modifies the buffer, and returns the new index into the buffer."
+ Modifies the buffer, and returns the new index into the buffer.
+ Watch out, this function turns off most type checking and all array bounds checking."
(declare (type (signed-byte 32) val)
(type (simple-array (unsigned-byte 8)) buffer)
(type fixnum index))
(locally (declare (optimize (speed 3) (safety 0) (debug 0)))
(loop repeat 4 doing
- (let ((byte (ldb #.(byte 8 0) val)))
+ (let ((byte (ldb (byte 8 0) val)))
(declare (type (unsigned-byte 8) byte))
(setq val (ash val -8))
(setf (aref buffer index) byte)
(defun encode-sfixed64 (val buffer index)
"Encodes the signed 32-bit integer 'val' as a fixed int into the buffer
at the given index.
- Modifies the buffer, and returns the new index into the buffer."
+ Modifies the buffer, and returns the new index into the buffer.
+ Watch out, this function turns off most type checking and all array bounds checking."
(declare (type (signed-byte 64) val)
(type (simple-array (unsigned-byte 8)) buffer)
(type fixnum index))
(locally (declare (optimize (speed 3) (safety 0) (debug 0)))
(loop repeat 8 doing
- (let ((byte (ldb #.(byte 8 0) val)))
+ (let ((byte (ldb (byte 8 0) val)))
(declare (type (unsigned-byte 8) byte))
(setq val (ash val -8))
(setf (aref buffer index) byte)
(defun encode-single (val buffer index)
"Encodes the single float 'val' into the buffer at the given index.
- Modifies the buffer, and returns the new index into the buffer."
+ Modifies the buffer, and returns the new index into the buffer.
+ Watch out, this function turns off most type checking and all array bounds checking."
(declare (type single-float val)
(type (simple-array (unsigned-byte 8)) buffer)
(type fixnum index))
(locally (declare (optimize (speed 3) (safety 0) (debug 0)))
(let ((bits (single-float-bits val)))
(loop repeat 4 doing
- (let ((byte (ldb #.(byte 8 0) bits)))
+ (let ((byte (ldb (byte 8 0) bits)))
(declare (type (unsigned-byte 8) byte))
(setq bits (ash bits -8))
(setf (aref buffer index) byte)
(defun encode-double (val buffer index)
"Encodes the double float 'val' into the buffer at the given index.
- Modifies the buffer, and returns the new index into the buffer."
+ Modifies the buffer, and returns the new index into the buffer.
+ Watch out, this function turns off most type checking and all array bounds checking."
(declare (type double-float val)
(type (simple-array (unsigned-byte 8)) buffer)
(type fixnum index))
(multiple-value-bind (low high)
(double-float-bits val)
(loop repeat 4 doing
- (let ((byte (ldb #.(byte 8 0) low)))
+ (let ((byte (ldb (byte 8 0) low)))
(declare (type (unsigned-byte 8) byte))
(setq low (ash low -8))
(setf (aref buffer index) byte)
(iincf index)))
(loop repeat 4 doing
- (let ((byte (ldb #.(byte 8 0) high)))
+ (let ((byte (ldb (byte 8 0) high)))
(declare (type (unsigned-byte 8) byte))
(setq high (ash high -8))
(setf (aref buffer index) byte)
(iincf index)))))
(values index buffer))
+(defun encode-string (string buffer index)
+ "Encodes the octets into the buffer at the given index.
+ Modifies the buffer, and returns the new index into the buffer.
+ Watch out, this function turns off most type checking and all array bounds checking."
+ (declare (type (simple-array (unsigned-byte 8)) buffer)
+ (type fixnum index))
+ (locally (declare (optimize (speed 3) (safety 0) (debug 0)))
+ (let* ((octets (babel:string-to-octets string :encoding :utf-8))
+ (len (length octets))
+ (idx (encode-uint32 len buffer index)))
+ (declare (type fixnum len)
+ (type (unsigned-byte 32) idx))
+ (replace buffer octets :start1 idx)
+ (values (i+ idx len) buffer))))
+
(defun encode-octets (octets buffer index)
"Encodes the octets into the buffer at the given index.
- Modifies the buffer, and returns the new index into the buffer."
+ Modifies the buffer, and returns the new index into the buffer.
+ Watch out, this function turns off most type checking and all array bounds checking."
(declare (type (simple-array (unsigned-byte 8)) buffer)
(type fixnum index))
(locally (declare (optimize (speed 3) (safety 0) (debug 0)))
;; then return the value and new index into the buffer
(defun decode-uint32 (buffer index)
"Decodes the next 32-bit varint integer in the buffer at the given index.
- Returns both the decoded value and the new index into the buffer."
+ Returns both the decoded value and the new index into the buffer.
+ Watch out, this function turns off most type checking and all array bounds checking."
+ (declare (optimize (speed 3) (safety 0) (debug 0)))
(declare (type (simple-array (unsigned-byte 8)) buffer)
(type fixnum index))
- (locally (declare (optimize (speed 3) (safety 0) (debug 0)))
- ;; Seven bits at a time, least significant bits first
- (loop with val = 0
- for places fixnum upfrom 0 by 7
- for byte fixnum = (prog1 (aref buffer index) (iincf index))
- do (setq val (logior val (ash (ldb #.(byte 7 0) byte) places)))
- until (i< byte 128)
- finally (progn
- (assert (< val #.(ash 1 32)) ()
- "The value ~D is longer than 32 bits" val)
- (return (values val index))))))
+ ;; Seven bits at a time, least significant bits first
+ (loop with val = 0
+ for places fixnum upfrom 0 by 7
+ for byte fixnum = (prog1 (aref buffer index) (iincf index))
+ do (setq val (logior val (ash (ldb (byte 7 0) byte) places)))
+ until (i< byte 128)
+ finally (progn
+ (assert (< val #.(ash 1 32)) ()
+ "The value ~D is longer than 32 bits" val)
+ (return (values val index)))))
(defun decode-uint64 (buffer index)
"Decodes the next 64-bit varint integer in the buffer at the given index.
- Returns both the decoded value and the new index into the buffer."
+ Returns both the decoded value and the new index into the buffer.
+ Watch out, this function turns off most type checking and all array bounds checking."
+ (declare (optimize (speed 3) (safety 0) (debug 0)))
(declare (type (simple-array (unsigned-byte 8)) buffer)
(type fixnum index))
- (locally (declare (optimize (speed 3) (safety 0) (debug 0)))
- ;; Seven bits at a time, least significant bits first
- (loop with val = 0
- for places fixnum upfrom 0 by 7
- for byte fixnum = (prog1 (aref buffer index) (iincf index))
- do (setq val (logior val (ash (ldb #.(byte 7 0) byte) places)))
- until (i< byte 128)
- finally (return (values val index)))))
+ ;; Seven bits at a time, least significant bits first
+ (loop with val = 0
+ for places fixnum upfrom 0 by 7
+ for byte fixnum = (prog1 (aref buffer index) (iincf index))
+ do (setq val (logior val (ash (ldb (byte 7 0) byte) places)))
+ until (i< byte 128)
+ finally (return (values val index))))
(defun decode-fixed32 (buffer index)
"Decodes the next 32-bit unsigned fixed integer in the buffer at the given index.
- Returns both the decoded value and the new index into the buffer."
+ Returns both the decoded value and the new index into the buffer.
+ Watch out, this function turns off most type checking and all array bounds checking."
(declare (type (simple-array (unsigned-byte 8)) buffer)
(type fixnum index))
(locally (declare (optimize (speed 3) (safety 0) (debug 0)))
(defun decode-sfixed32 (buffer index)
"Decodes the next 32-bit signed fixed integer in the buffer at the given index.
- Returns both the decoded value and the new index into the buffer."
+ Returns both the decoded value and the new index into the buffer.
+ Watch out, this function turns off most type checking and all array bounds checking."
(declare (type (simple-array (unsigned-byte 8)) buffer)
(type fixnum index))
(locally (declare (optimize (speed 3) (safety 0) (debug 0)))
for places fixnum upfrom 0 by 8
for byte fixnum = (prog1 (aref buffer index) (iincf index))
do (setq val (logior val (ash byte places))))
- (when (i= (ldb #.(byte 1 31) val) 1) ;sign bit set, so negative value
+ (when (i= (ldb (byte 1 31) val) 1) ;sign bit set, so negative value
(decf val #.(ash 1 32)))
(values val index))))
(defun decode-fixed64 (buffer index)
"Decodes the next unsigned 64-bit fixed integer in the buffer at the given index.
- Returns both the decoded value and the new index into the buffer."
+ Returns both the decoded value and the new index into the buffer.
+ Watch out, this function turns off most type checking and all array bounds checking."
(declare (type (simple-array (unsigned-byte 8)) buffer)
(type fixnum index))
(locally (declare (optimize (speed 3) (safety 0) (debug 0)))
(defun decode-sfixed64 (buffer index)
"Decodes the next signed 64-bit fixed integer in the buffer at the given index.
- Returns both the decoded value and the new index into the buffer."
+ Returns both the decoded value and the new index into the buffer.
+ Watch out, this function turns off most type checking and all array bounds checking."
(declare (type (simple-array (unsigned-byte 8)) buffer)
(type fixnum index))
(locally (declare (optimize (speed 3) (safety 0) (debug 0)))
for places fixnum upfrom 0 by 8
for byte fixnum = (prog1 (aref buffer index) (iincf index))
do (setq val (logior val (ash byte places))))
- (when (i= (ldb #.(byte 1 63) val) 1) ;sign bit set, so negative value
+ (when (i= (ldb (byte 1 63) val) 1) ;sign bit set, so negative value
(decf val #.(ash 1 64)))
(values val index))))
(defun decode-single (buffer index)
"Decodes the next single float in the buffer at the given index.
- Returns both the decoded value and the new index into the buffer."
+ Returns both the decoded value and the new index into the buffer.
+ Watch out, this function turns off most type checking and all array bounds checking."
(declare (type (simple-array (unsigned-byte 8)) buffer)
(type fixnum index))
(locally (declare (optimize (speed 3) (safety 0) (debug 0)))
for places fixnum upfrom 0 by 8
for byte fixnum = (prog1 (aref buffer index) (iincf index))
do (setq bits (logior bits (ash byte places))))
- (when (i= (ldb #.(byte 1 31) bits) 1) ;sign bit set, so negative value
+ (when (i= (ldb (byte 1 31) bits) 1) ;sign bit set, so negative value
(decf bits #.(ash 1 32)))
(values (make-single-float bits) index))))
(defun decode-double (buffer index)
"Decodes the next double float in the buffer at the given index.
- Returns both the decoded value and the new index into the buffer."
+ Returns both the decoded value and the new index into the buffer.
+ Watch out, this function turns off most type checking and all array bounds checking."
(declare (type (simple-array (unsigned-byte 8)) buffer)
(type fixnum index))
(locally (declare (optimize (speed 3) (safety 0) (debug 0)))
for byte fixnum = (prog1 (aref buffer index) (iincf index))
do (setq high (logior high (ash byte places))))
;; High bits are signed, but low bits are unsigned
- (when (i= (ldb #.(byte 1 31) high) 1) ;sign bit set, so negative value
+ (when (i= (ldb (byte 1 31) high) 1) ;sign bit set, so negative value
(decf high #.(ash 1 32)))
(values (make-double-float low high) index))))
+(defun decode-string (buffer index)
+ "Decodes the next UTF-8 encoded string in the buffer at the given index.
+ Returns both the decoded string and the new index into the buffer.
+ Watch out, this function turns off most type checking and all array bounds checking."
+ (declare (type (simple-array (unsigned-byte 8)) buffer)
+ (type fixnum index))
+ (locally (declare (optimize (speed 3) (safety 0) (debug 0)))
+ (multiple-value-bind (len idx)
+ (decode-uint32 buffer index)
+ (declare (type (unsigned-byte 32) len)
+ (type fixnum idx))
+ (values (babel:octets-to-string buffer :start idx :end (i+ idx len) :encoding :utf-8) (i+ idx len)))))
+
(defun decode-octets (buffer index)
"Decodes the next octets in the buffer at the given index.
- Returns both the decoded value and the new index into the buffer."
+ Returns both the decoded value and the new index into the buffer.
+ Watch out, this function turns off most type checking and all array bounds checking."
(declare (type (simple-array (unsigned-byte 8)) buffer)
(type fixnum index))
(locally (declare (optimize (speed 3) (safety 0) (debug 0)))
(defun length32 (val)
"Returns the length that 'val' will take when encoded as a 32-bit integer."
- (assert (< val #.(ash 1 32)) ()
- "The value ~D is longer than 32 bits" val)
- (locally (declare (optimize (speed 3) (safety 0) (debug 0)))
- (let ((size 0))
- (declare (type fixnum size))
- (loop do (progn
- (setq val (ash val -7))
- (iincf size))
- until (zerop val))
- size)))
+ (declare (optimize (speed 3) (safety 0) (debug 0)))
+ (let ((size 0))
+ (declare (type fixnum size))
+ (loop do (progn
+ (setq val (ash val -7))
+ (iincf size))
+ until (zerop val))
+ size))
(defun length64 (val)
"Returns the length that 'val' will take when encoded as a 64-bit integer."
- (locally (declare (optimize (speed 3) (safety 0) (debug 0)))
- (let ((size 0))
- (declare (type fixnum size))
- (loop do (progn
- (setq val (ash val -7))
- (iincf size))
- until (zerop val))
- size)))
+ (declare (optimize (speed 3) (safety 0) (debug 0)))
+ (let ((size 0))
+ (declare (type fixnum size))
+ (loop do (progn
+ (setq val (ash val -7))
+ (iincf size))
+ until (zerop val))
+ size))
;;; Skipping elements
-(defun skip-element (buffer index wire-type)
+(defun skip-element (buffer index tag)
"Skip an element in the buffer at the index of the given wire type.
- Returns the new index in the buffer."
+ Returns the new index in the buffer.
+ Watch out, this function turns off all type checking and all array bounds checking."
+ (declare (optimize (speed 3) (safety 0) (debug 0)))
(declare (type (simple-array (unsigned-byte 8)) buffer)
(type fixnum index)
- (type (unsigned-byte 32) wire-type))
- (locally (declare (optimize (speed 3) (safety 0) (debug 0)))
- (case wire-type
- (($wire-type-varint)
- (loop for byte fixnum = (prog1 (aref buffer index) (iincf index))
- until (i< byte 128))
- index)
- (($wire-type-string)
- (multiple-value-bind (len idx)
- (decode-uint32 buffer index)
- (declare (type (unsigned-byte 32) len)
- (type fixnum idx))
- (i+ idx len)))
- (($wire-type-32bit)
- (i+ index 4))
- (($wire-type-64bit)
- (i+ index 8)))))
+ (type (unsigned-byte 32) tag))
+ (case (ilogand tag #x7)
+ (($wire-type-varint)
+ (loop for byte fixnum = (prog1 (aref buffer index) (iincf index))
+ until (i< byte 128))
+ index)
+ (($wire-type-string)
+ (multiple-value-bind (len idx)
+ (decode-uint32 buffer index)
+ (declare (type (unsigned-byte 32) len)
+ (type fixnum idx))
+ (i+ idx len)))
+ (($wire-type-32bit)
+ (i+ index 4))
+ (($wire-type-64bit)
+ (i+ index 8))
+ (($wire-type-start-group)
+ (loop (multiple-value-bind (new-tag idx)
+ (decode-uint32 buffer index)
+ (cond ((not (i= (ilogand new-tag #x7) $wire-type-start-group))
+ (setq index (skip-element buffer idx new-tag)))
+ ;; Clever test for matching end group number
+ ((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"))))))
+ (t index)))