Repository: prometheus/prometheus
File: model/labels/labels_stringlabels.go (Go)

Code before:
	}
	return Labels{data: yoloString(buf)}
}

func marshalLabelsToSizedBuffer(lbls []Label, data []byte) int {
	i := len(data)
	for index := len(lbls) - 1; index >= 0; index-- {
		size := marshalLabelToSizedBuffer(&lbls[index], data[:i])
		i -= size
	}
	return len(data) - i
}

func marshalLabelToSizedBuffer(m *Label, data []byte) int {
	i := len(data)
	i -= len(m.Value)
	copy(data[i:], m.Value)
	i = encodeSize(data, i, len(m.Value))
	i -= len(m.Name)
	copy(data[i:], m.Name)
	i = encodeSize(data, i, len(m.Name))
	return len(data) - i
}

func sizeWhenEncoded(x uint64) (n int) {
	if x < 254 {
		return 1
	}
	return 4
}

func encodeSize(data []byte, offset, v int) int {
	if v < 255 {
		offset--
		data[offset] = uint8(v)
		return offset
	}
	offset -= 4
	data[offset] = 255
	data[offset+1] = byte(v)
	data[offset+2] = byte((v >> 8))
	data[offset+3] = byte((v >> 16))
	return offset
}

func labelsSize(lbls []Label) (n int) {
	// we just encode name/value/name/value, without any extra tags or length bytes
	for _, e := range lbls {
		n += labelSize(&e)
	}
	return n

Review comment (suggestion):
```suggestion
	if x < 255 {
```

Maybe should be a test on the boundary case? (Probably not as below, that was the quickest place to put it).

```
panic: runtime error: index out of range [288] with length 288 [recovered]
        panic: runtime error: index out of range [288] with length 288 [recovered]
        panic: runtime error: index out of range [288] with length 288
```

```
diff --git a/model/labels/labels_stringlabels.go b/model/labels/labels_stringlabels.go
index c542b3d51..6ba5a51f5 100644
--- a/model/labels/labels_stringlabels.go
+++ b/model/labels/labels_stringlabels.go
@@ -521,7 +521,7 @@ func marshalLabelToSizedBuffer(m *Label, data []byte) int {
 }
 
 func sizeWhenEncoded(x uint64) (n int) {
-	if x < 254 {
+	if x < 255 {
 		return 1
 	}
 	return 4
diff --git a/model/labels/labels_test.go b/model/labels/labels_test.go
index 06802d6f3..3ebfe0d38 100644
--- a/model/labels/labels_test.go
+++ b/model/labels/labels_test.go
@@ -954,8 +954,8 @@ func BenchmarkLabels_Copy(b *testing.B) {
 }
 
 func TestMarshaling(t *testing.T) {
-	lbls := FromStrings("aaa", "111", "bbb", "2222", "ccc", "33333")
-	expectedJSON := "{\"aaa\":\"111\",\"bbb\":\"2222\",\"ccc\":\"33333\"}"
+	lbls := FromStrings("aaa", "111", "bbb", "2222", "ccc", "33333", "xx", strings.Repeat("x", 254))
+	expectedJSON := "{\"aaa\":\"111\",\"bbb\":\"2222\",\"ccc\":\"33333\",\"xx\":\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"}"
 	b, err := json.Marshal(lbls)
 	require.NoError(t, err)
 	require.JSONEq(t, expectedJSON, string(b))
@@ -965,7 +965,7 @@ func TestMarshaling(t *testing.T) {
 	require.NoError(t, err)
 	require.Equal(t, lbls, gotJ)
 
-	expectedYAML := "aaa: \"111\"\nbbb: \"2222\"\nccc: \"33333\"\n"
+	expectedYAML := "aaa: \"111\"\nbbb: \"2222\"\nccc: \"33333\"\nxx: \"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n"
 	b, err = yaml.Marshal(lbls)
 	require.NoError(t, err)
 	require.YAMLEq(t, expectedYAML, string(b))
@@ -993,7 +993,7 @@ func TestMarshaling(t *testing.T) {
 
 	b, err = yaml.Marshal(f)
 	require.NoError(t, err)
-	expectedYAMLFromStruct := "a_labels:\n  aaa: \"111\"\n  bbb: \"2222\"\n  ccc: \"33333\"\n"
+	expectedYAMLFromStruct := "a_labels:\n  aaa: \"111\"\n  bbb: \"2222\"\n  ccc: \"33333\"\n  xx: \"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n"
 	require.YAMLEq(t, expectedYAMLFromStruct, string(b))
 
 	var gotFY foo
```

Code after:
		buf = appendLabelTo(buf, &b.add[a])
	}
	return Labels{data: yoloString(buf)}
}

func marshalLabelsToSizedBuffer(lbls []Label, data []byte) int {
	i := len(data)
	for index := len(lbls) - 1; index >= 0; index-- {
		size := marshalLabelToSizedBuffer(&lbls[index], data[:i])
		i -= size
	}
	return len(data) - i
}

func marshalLabelToSizedBuffer(m *Label, data []byte) int {
	i := len(data)
	i -= len(m.Value)
	copy(data[i:], m.Value)
	i = encodeSize(data, i, len(m.Value))
	i -= len(m.Name)
	copy(data[i:], m.Name)
	i = encodeSize(data, i, len(m.Name))
	return len(data) - i
}

func sizeWhenEncoded(x uint64) (n int) {
	if x < 255 {
		return 1
	} else if x <= 1<<24 {
		return 4
	}
	panic("String too long to encode as label.")
}

func encodeSize(data []byte, offset, v int) int {
	if v < 255 {
		offset--
		data[offset] = uint8(v)
		return offset
	}
	offset -= 4
	data[offset] = 255
	data[offset+1] = byte(v)
	data[offset+2] = byte((v >> 8))
	data[offset+3] = byte((v >> 16))
	return offset
}

func labelsSize(lbls []Label) (n int) {
	// we just encode name/value/name/value, without any extra tags or length bytes
	for _, e := range lbls {