- (print-unreadable-object (f stream :type t :identity t)
- (format stream "~S :: ~S = ~D~@[ (group~*)~]~@[ (extended~*)~]"
- (proto-value f) (proto-class f) (proto-index f)
- (eq (proto-message-type f) :group)
- (eq (proto-message-type f) :extends))))
+ (if *print-escape*
+ (print-unreadable-object (f stream :type t :identity t)
+ (format stream "~S :: ~S = ~D~@[ (group~*)~]~@[ (extended~*)~]"
+ (proto-value f)
+ (and (slot-boundp f 'class) (proto-class f))
+ (proto-index f)
+ (eq (proto-message-type f) :group)
+ (eq (proto-message-type f) :extends)))
+ (format stream "~S" (proto-value f))))
+
+;; The 'value' slot really holds the name of the slot,
+;; so let's give it a better name
+(defmethod proto-slot ((field protobuf-field))
+ (proto-value field))
+
+(defmethod (setf proto-slot) (slot (field protobuf-field))
+ (setf (proto-value field) slot))
+
+(defgeneric empty-default-p (field)
+ (:documentation
+ "Returns true iff the default for the field is empty, ie, was not supplied.")
+ (:method ((field protobuf-field))
+ (let ((default (proto-default field)))
+ (or (eq default $empty-default)
+ (eq default $empty-list)
+ (eq default $empty-vector)
+ ;; Special handling for imported CLOS classes
+ (and (not (eq (proto-required field) :optional))
+ (or (null default) (equalp default #())))))))
+
+(defgeneric vector-field-p (field)
+ (:documentation
+ "Returns true if the storage for a 'repeated' field is a vector,
+ returns false if the storage is a list.")
+ (:method ((field protobuf-field))
+ (let ((default (proto-default field)))
+ (or (eq default $empty-vector)
+ (and (vectorp default) (not (stringp default)))))))