+(defmethod find-option ((protobuf base-protobuf) (name string))
+ (let ((option (find name (proto-options protobuf) :key #'proto-name :test #'option-name=)))
+ (if option
+ (values (proto-value option) (proto-type option) t)
+ (values nil nil nil))))
+
+(defmethod find-option ((options list) (name string))
+ (let ((option (find name options :key #'proto-name :test #'option-name=)))
+ (if option
+ (values (proto-value option) (proto-type option) t)
+ (values nil nil nil))))
+
+(defgeneric add-option (protobuf name value &optional type)
+ (:documentation
+ "Given a Protobufs schema, message, enum, etc
+ add the option called 'name' with the value 'value' and type 'type'.
+ If the option was previoously present, it is replaced."))
+
+(defmethod add-option ((protobuf base-protobuf) (name string) value &optional (type 'string))
+ (let ((option (find name (proto-options protobuf) :key #'proto-name :test #'option-name=)))
+ (if option
+ ;; This side-effects the old option
+ (setf (proto-value option) value
+ (proto-type option) type)
+ ;; This side-effects 'proto-options'
+ (setf (proto-options protobuf)
+ (append (proto-options protobuf)
+ (list (make-option name value type)))))))
+
+(defmethod add-option ((options list) (name string) value &optional (type 'string))
+ (let ((option (find name options :key #'proto-name :test #'option-name=)))
+ (append (remove option options)
+ (list (make-option name value type)))))
+
+(defgeneric remove-options (protobuf &rest names)
+ (:documentation
+ "Given a Protobufs schema, message, enum, etc and a set of option names,
+ remove all of those options from the set of options."))
+
+(defmethod remove-options ((protobuf base-protobuf) &rest names)
+ (dolist (name names (proto-options protobuf))
+ (let ((option (find name (proto-options protobuf) :key #'proto-name :test #'option-name=)))
+ (when option
+ ;; This side-effects 'proto-options'
+ (setf (proto-options protobuf) (remove option (proto-options protobuf)))))))
+
+(defmethod remove-options ((options list) &rest names)
+ (dolist (name names options)
+ (let ((option (find name options :key #'proto-name :test #'option-name=)))
+ (when option
+ ;; This does not side-effect the list of options
+ (setq options (remove option options))))))
+
+(defun option-name= (name1 name2)
+ (let* ((name1 (string name1))
+ (name2 (string name2))
+ (start1 (if (eql (char name1 0) #\() 1 0))
+ (start2 (if (eql (char name2 0) #\() 1 0))
+ (end1 (if (eql (char name1 0) #\() (- (length name1) 1) (length name1)))
+ (end2 (if (eql (char name2 0) #\() (- (length name2) 1) (length name2))))
+ (string= name1 name2 :start1 start1 :end1 end1 :start2 start2 :end2 end2)))
+
+
+;; A Protobufs enumeration