encoding/openapi: make OrderedMap type opaque

The OrderedMap needs to be a pointer, which may be
a bit unintuitive it being a slice. Change it to as struct.

Info is left as a non-pointer to indicate the non-optional
nature of it. The user of pointers is enforced by making
MarshalJSON only work for pointer types.

Change-Id: I8481dd8974825928815bfef3acd1eb5fc0274029
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/2460
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/encoding/openapi/orderedmap.go b/encoding/openapi/orderedmap.go
index 8d419a8..91a2ec4 100644
--- a/encoding/openapi/orderedmap.go
+++ b/encoding/openapi/orderedmap.go
@@ -18,7 +18,9 @@
 
 // An OrderedMap is a set of key-value pairs that preserves the order in which
 // items were added. It marshals to JSON as an object.
-type OrderedMap []KeyValue
+type OrderedMap struct {
+	kvs []KeyValue
+}
 
 // KeyValue associates a value with a key.
 type KeyValue struct {
@@ -26,26 +28,37 @@
 	Value interface{}
 }
 
-func (m *OrderedMap) prepend(key string, value interface{}) {
-	*m = append([]KeyValue{{key, value}}, (*m)...)
+// Pairs returns the KeyValue pairs associated with m.
+func (m *OrderedMap) Pairs() []KeyValue {
+	return m.kvs
 }
 
-// set sets a key value pair. If a pair with the same key already existed, it
+func (m *OrderedMap) prepend(key string, value interface{}) {
+	m.kvs = append([]KeyValue{{key, value}}, m.kvs...)
+}
+
+// Set sets a key value pair. If a pair with the same key already existed, it
 // will be replaced with the new value. Otherwise, the new value is added to
 // the end.
-func (m *OrderedMap) set(key string, value interface{}) {
-	for i, v := range *m {
+func (m *OrderedMap) Set(key string, value interface{}) {
+	for i, v := range m.kvs {
 		if v.Key == key {
-			(*m)[i].Value = value
+			m.kvs[i].Value = value
 			return
 		}
 	}
-	*m = append(*m, KeyValue{key, value})
+	m.kvs = append(m.kvs, KeyValue{key, value})
+}
+
+// SetAll replaces existing key-value pairs with the given ones. The keys must
+// be unique.
+func (m *OrderedMap) SetAll(kvs []KeyValue) {
+	m.kvs = kvs
 }
 
 // exists reports whether a key-value pair exists for the given key.
-func (m OrderedMap) exists(key string) bool {
-	for _, v := range m {
+func (m *OrderedMap) exists(key string) bool {
+	for _, v := range m.kvs {
 		if v.Key == key {
 			return true
 		}
@@ -53,10 +66,13 @@
 	return false
 }
 
-// MarshalJSON implements Marshal
-func (m OrderedMap) MarshalJSON() (b []byte, err error) {
+// MarshalJSON implements json.Marshaler.
+func (m *OrderedMap) MarshalJSON() (b []byte, err error) {
+	// This is a pointer receiever to enforce that we only store pointers to
+	// OrderedMap in the output.
+
 	b = append(b, '{')
-	for i, v := range m {
+	for i, v := range m.kvs {
 		if i > 0 {
 			b = append(b, ",\n"...)
 		}