Просмотр исходного кода

Enforce unique mapping keys and drop the option.

Gustavo Niemeyer 7 лет назад
Родитель
Сommit
309c9d1575
3 измененных файлов с 34 добавлено и 34 удалено
  1. 19 12
      decode.go
  2. 15 14
      decode_test.go
  3. 0 8
      yaml.go

+ 19 - 12
decode.go

@@ -348,7 +348,7 @@ var (
 )
 
 func newDecoder() *decoder {
-	d := &decoder{mapType: defaultMapType}
+	d := &decoder{mapType: defaultMapType, uniqueKeys: true}
 	d.aliases = make(map[*Node]bool)
 	return d
 }
@@ -698,6 +698,22 @@ func (d *decoder) sequence(n *Node, out reflect.Value) (good bool) {
 }
 
 func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
+	l := len(n.Children)
+	if d.uniqueKeys {
+		nerrs := len(d.terrors)
+		for i := 0; i < l; i += 2 {
+			ni := n.Children[i]
+			for j := i+2; j < l; j += 2 {
+				nj := n.Children[j]
+				if ni.Kind == nj.Kind && ni.Value == nj.Value {
+					d.terrors = append(d.terrors, fmt.Sprintf("line %d: mapping key %#v already defined at line %d", nj.Line, nj.Value, ni.Line))
+				}
+			}
+		}
+		if len(d.terrors) > nerrs {
+			return false
+		}
+	}
 	switch out.Kind() {
 	case reflect.Struct:
 		return d.mappingStruct(n, out)
@@ -723,7 +739,6 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
 	if out.IsNil() {
 		out.Set(reflect.MakeMap(outt))
 	}
-	l := len(n.Children)
 	for i := 0; i < l; i += 2 {
 		if isMerge(n.Children[i]) {
 			d.merge(n.Children[i+1], out)
@@ -740,7 +755,7 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
 			}
 			e := reflect.New(et).Elem()
 			if d.unmarshal(n.Children[i+1], e) {
-				d.setMapIndex(n.Children[i+1], out, k, e)
+				out.SetMapIndex(k, e)
 			}
 		}
 	}
@@ -748,14 +763,6 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
 	return true
 }
 
-func (d *decoder) setMapIndex(n *Node, out, k, v reflect.Value) {
-	if d.uniqueKeys && out.MapIndex(k) != zeroValue {
-		d.terrors = append(d.terrors, fmt.Sprintf("line %d: key %#v already set in map", n.Line, k.Interface()))
-		return
-	}
-	out.SetMapIndex(k, v)
-}
-
 func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
 	sinfo, err := getStructInfo(out.Type())
 	if err != nil {
@@ -806,7 +813,7 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
 			}
 			value := reflect.New(elemType).Elem()
 			d.unmarshal(n.Children[i+1], value)
-			d.setMapIndex(n.Children[i+1], inlineMap, name, value)
+			inlineMap.SetMapIndex(name, value)
 		} else if d.knownFields {
 			d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.Line, name.String(), out.Type()))
 		}

+ 15 - 14
decode_test.go

@@ -1211,7 +1211,7 @@ var unmarshalStrictTests = []struct {
 	unique: true,
 	data:   "a: 1\nb: 2\na: 3\n",
 	value:  struct{ A, B int }{A: 3, B: 2},
-	error:  `yaml: unmarshal errors:\n  line 3: field a already set in type struct { A int; B int }`,
+	error: `yaml: unmarshal errors:\n  line 3: mapping key "a" already defined at line 1`,
 }, {
 	unique: true,
 	data:   "c: 3\na: 1\nb: 2\nc: 4\n",
@@ -1227,7 +1227,7 @@ var unmarshalStrictTests = []struct {
 			},
 		},
 	},
-	error: `yaml: unmarshal errors:\n  line 4: field c already set in type struct { A int; yaml_test.inlineB "yaml:\\",inline\\"" }`,
+	error: `yaml: unmarshal errors:\n  line 4: mapping key "c" already defined at line 1`,
 }, {
 	unique: true,
 	data:   "c: 0\na: 1\nb: 2\nc: 1\n",
@@ -1243,7 +1243,7 @@ var unmarshalStrictTests = []struct {
 			},
 		},
 	},
-	error: `yaml: unmarshal errors:\n  line 4: field c already set in type struct { A int; yaml_test.inlineB "yaml:\\",inline\\"" }`,
+	error: `yaml: unmarshal errors:\n  line 4: mapping key "c" already defined at line 1`,
 }, {
 	unique: true,
 	data:   "c: 1\na: 1\nb: 2\nc: 3\n",
@@ -1257,7 +1257,7 @@ var unmarshalStrictTests = []struct {
 			"c": 3,
 		},
 	},
-	error: `yaml: unmarshal errors:\n  line 4: key "c" already set in map`,
+	error: `yaml: unmarshal errors:\n  line 4: mapping key "c" already defined at line 1`,
 }, {
 	unique: true,
 	data:   "a: 1\n9: 2\nnull: 3\n9: 4",
@@ -1266,26 +1266,27 @@ var unmarshalStrictTests = []struct {
 		nil: 3,
 		9:   4,
 	},
-	error: `yaml: unmarshal errors:\n  line 4: key 9 already set in map`,
+	error: `yaml: unmarshal errors:\n  line 4: mapping key "9" already defined at line 2`,
 }}
 
 func (s *S) TestUnmarshalKnownFields(c *C) {
 	for i, item := range unmarshalStrictTests {
 		c.Logf("test %d: %q", i, item.data)
 		// First test that normal Unmarshal unmarshals to the expected value.
-		t := reflect.ValueOf(item.value).Type()
-		value := reflect.New(t)
-		err := yaml.Unmarshal([]byte(item.data), value.Interface())
-		c.Assert(err, Equals, nil)
-		c.Assert(value.Elem().Interface(), DeepEquals, item.value)
+		if !item.unique {
+			t := reflect.ValueOf(item.value).Type()
+			value := reflect.New(t)
+			err := yaml.Unmarshal([]byte(item.data), value.Interface())
+			c.Assert(err, Equals, nil)
+			c.Assert(value.Elem().Interface(), DeepEquals, item.value)
+		}
 
 		// Then test that it fails on the same thing with KnownFields on.
-		t = reflect.ValueOf(item.value).Type()
-		value = reflect.New(t)
+		t := reflect.ValueOf(item.value).Type()
+		value := reflect.New(t)
 		dec := yaml.NewDecoder(bytes.NewBuffer([]byte(item.data)))
 		dec.KnownFields(item.known)
-		dec.UniqueKeys(item.unique)
-		err = dec.Decode(value.Interface())
+		err := dec.Decode(value.Interface())
 		c.Assert(err, ErrorMatches, item.error)
 	}
 }

+ 0 - 8
yaml.go

@@ -77,7 +77,6 @@ func Unmarshal(in []byte, out interface{}) (err error) {
 type Decoder struct {
 	parser      *parser
 	knownFields bool
-	uniqueKeys  bool
 }
 
 // NewDecoder returns a new decoder that reads from r.
@@ -96,12 +95,6 @@ func (dec *Decoder) KnownFields(enable bool) {
 	dec.knownFields = enable
 }
 
-// UniqueKeys enforces the keys in decoded mappings to exist
-// only once inside the given mapping.
-func (dec *Decoder) UniqueKeys(enable bool) {
-	dec.uniqueKeys = enable
-}
-
 // Decode reads the next YAML-encoded value from its input
 // and stores it in the value pointed to by v.
 //
@@ -110,7 +103,6 @@ func (dec *Decoder) UniqueKeys(enable bool) {
 func (dec *Decoder) Decode(v interface{}) (err error) {
 	d := newDecoder()
 	d.knownFields = dec.knownFields
-	d.uniqueKeys = dec.uniqueKeys
 	defer handleErr(&err)
 	node := dec.parser.parse()
 	if node == nil {