[chore] [pdata] Migrate the generator to go templates (#7241)

This commit is contained in:
Dmitrii Anoshin 2023-02-27 09:05:50 -08:00 committed by GitHub
parent 6f800ca227
commit 1f5865df1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 808 additions and 882 deletions

File diff suppressed because it is too large Load Diff

View File

@ -16,35 +16,35 @@ package internal // import "go.opentelemetry.io/collector/pdata/internal/cmd/pda
import (
"bytes"
"os"
"text/template"
)
const commonSliceTemplate = `// ${structName} logically represents a slice of ${elementName}.
const sliceTemplate = `// {{ .structName }} logically represents a slice of {{ .elementName }}.
//
// This is a reference type. If passed by value and callee modifies it, the
// caller will see the modification.
//
// Must use New${structName} function to create new instances.
// Must use New{{ .structName }} function to create new instances.
// Important: zero-initialized instance is not valid for use.
type ${structName} struct {
orig *[]${originElementType}
type {{ .structName }} struct {
orig *[]{{ .originElementType }}
}
func new${structName}(orig *[]${originElementType}) ${structName} {
return ${structName}{orig}
func new{{ .structName }}(orig *[]{{ .originElementType }}) {{ .structName }} {
return {{ .structName }}{orig}
}
// New${structName} creates a ${structName} with 0 elements.
// New{{ .structName }} creates a {{ .structName }} with 0 elements.
// Can use "EnsureCapacity" to initialize with a given capacity.
func New${structName}() ${structName} {
orig := []${originElementType}(nil)
return new${structName}(&orig)
func New{{ .structName }}() {{ .structName }} {
orig := []{{ .originElementType }}(nil)
return new{{ .structName }}(&orig)
}
// Len returns the number of elements in the slice.
//
// Returns "0" for a newly instance created with "New${structName}()".
func (es ${structName}) Len() int {
// Returns "0" for a newly instance created with "New{{ .structName }}()".
func (es {{ .structName }}) Len() int {
return len(*es.orig)
}
@ -55,42 +55,42 @@ func (es ${structName}) Len() int {
// e := es.At(i)
// ... // Do something with the element
// }
func (es ${structName}) At(i int) ${elementName} {
return ${newElement}
func (es {{ .structName }}) At(i int) {{ .elementName }} {
return {{ .newElement }}
}
// EnsureCapacity is an operation that ensures the slice has at least the specified capacity.
// 1. If the newCap <= cap then no change in capacity.
// 2. If the newCap > cap then the slice capacity will be expanded to equal newCap.
//
// Here is how a new ${structName} can be initialized:
// es := New${structName}()
// Here is how a new {{ .structName }} can be initialized:
// es := New{{ .structName }}()
// es.EnsureCapacity(4)
// for i := 0; i < 4; i++ {
// e := es.AppendEmpty()
// // Here should set all the values for e.
// }
func (es ${structName}) EnsureCapacity(newCap int) {
func (es {{ .structName }}) EnsureCapacity(newCap int) {
oldCap := cap(*es.orig)
if newCap <= oldCap {
return
}
newOrig := make([]${originElementType}, len(*es.orig), newCap)
newOrig := make([]{{ .originElementType }}, len(*es.orig), newCap)
copy(newOrig, *es.orig)
*es.orig = newOrig
}
// AppendEmpty will append to the end of the slice an empty ${elementName}.
// It returns the newly added ${elementName}.
func (es ${structName}) AppendEmpty() ${elementName} {
*es.orig = append(*es.orig, ${emptyOriginElement})
// AppendEmpty will append to the end of the slice an empty {{ .elementName }}.
// It returns the newly added {{ .elementName }}.
func (es {{ .structName }}) AppendEmpty() {{ .elementName }} {
*es.orig = append(*es.orig, {{ .emptyOriginElement }})
return es.At(es.Len() - 1)
}
// MoveAndAppendTo moves all elements from the current slice and appends them to the dest.
// The current slice will be cleared.
func (es ${structName}) MoveAndAppendTo(dest ${structName}) {
func (es {{ .structName }}) MoveAndAppendTo(dest {{ .structName }}) {
if *dest.orig == nil {
// We can simply move the entire vector and avoid any allocations.
*dest.orig = *es.orig
@ -102,7 +102,7 @@ func (es ${structName}) MoveAndAppendTo(dest ${structName}) {
// RemoveIf calls f sequentially for each element present in the slice.
// If f returns true, the element is removed from the slice.
func (es ${structName}) RemoveIf(f func(${elementName}) bool) {
func (es {{ .structName }}) RemoveIf(f func({{ .elementName }}) bool) {
newLen := 0
for i := 0; i < len(*es.orig); i++ {
if f(es.At(i)) {
@ -118,76 +118,117 @@ func (es ${structName}) RemoveIf(f func(${elementName}) bool) {
}
// TODO: Prevent memory leak by erasing truncated values.
*es.orig = (*es.orig)[:newLen]
}`
}
const commonSliceTestTemplate = `func Test${structName}(t *testing.T) {
es := New${structName}()
// CopyTo copies all elements from the current slice overriding the destination.
func (es {{ .structName }}) CopyTo(dest {{ .structName }}) {
srcLen := es.Len()
destCap := cap(*dest.orig)
if srcLen <= destCap {
(*dest.orig) = (*dest.orig)[:srcLen:destCap]
{{- if eq .type "sliceOfPtrs" }}
for i := range *es.orig {
new{{ .elementName }}((*es.orig)[i]).CopyTo(new{{ .elementName }}((*dest.orig)[i]))
}
return
}
origs := make([]{{ .originName }}, srcLen)
wrappers := make([]*{{ .originName }}, srcLen)
for i := range *es.orig {
wrappers[i] = &origs[i]
new{{ .elementName }}((*es.orig)[i]).CopyTo(new{{ .elementName }}(wrappers[i]))
}
*dest.orig = wrappers
{{- else }}
} else {
(*dest.orig) = make([]{{ .originElementType }}, srcLen)
}
for i := range *es.orig {
{{ .newElement }}.CopyTo(new{{ .elementName }}(&(*dest.orig)[i]))
}
{{- end }}
}
{{ if eq .type "sliceOfPtrs" -}}
// Sort sorts the {{ .elementName }} elements within {{ .structName }} given the
// provided less function so that two instances of {{ .structName }}
// can be compared.
func (es {{ .structName }}) Sort(less func(a, b {{ .elementName }}) bool) {
sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) })
}
{{- end }}`
const sliceTestTemplate = `func Test{{ .structName }}(t *testing.T) {
es := New{{ .structName }}()
assert.Equal(t, 0, es.Len())
es = new${structName}(&[]${originElementType}{})
es = new{{ .structName }}(&[]{{ .originElementType }}{})
assert.Equal(t, 0, es.Len())
emptyVal := New${elementName}()
testVal := generateTest${elementName}()
emptyVal := New{{ .elementName }}()
testVal := generateTest{{ .elementName }}()
for i := 0; i < 7; i++ {
el := es.AppendEmpty()
assert.Equal(t, emptyVal, es.At(i))
fillTest${elementName}(el)
fillTest{{ .elementName }}(el)
assert.Equal(t, testVal, es.At(i))
}
assert.Equal(t, 7, es.Len())
}
func Test${structName}_CopyTo(t *testing.T) {
dest := New${structName}()
func Test{{ .structName }}_CopyTo(t *testing.T) {
dest := New{{ .structName }}()
// Test CopyTo to empty
New${structName}().CopyTo(dest)
assert.Equal(t, New${structName}(), dest)
New{{ .structName }}().CopyTo(dest)
assert.Equal(t, New{{ .structName }}(), dest)
// Test CopyTo larger slice
generateTest${structName}().CopyTo(dest)
assert.Equal(t, generateTest${structName}(), dest)
generateTest{{ .structName }}().CopyTo(dest)
assert.Equal(t, generateTest{{ .structName }}(), dest)
// Test CopyTo same size slice
generateTest${structName}().CopyTo(dest)
assert.Equal(t, generateTest${structName}(), dest)
generateTest{{ .structName }}().CopyTo(dest)
assert.Equal(t, generateTest{{ .structName }}(), dest)
}
func Test${structName}_EnsureCapacity(t *testing.T) {
es := generateTest${structName}()
func Test{{ .structName }}_EnsureCapacity(t *testing.T) {
es := generateTest{{ .structName }}()
// Test ensure smaller capacity.
const ensureSmallLen = 4
es.EnsureCapacity(ensureSmallLen)
assert.Less(t, ensureSmallLen, es.Len())
assert.Equal(t, es.Len(), cap(*es.orig))
assert.Equal(t, generateTest${structName}(), es)
assert.Equal(t, generateTest{{ .structName }}(), es)
// Test ensure larger capacity
const ensureLargeLen = 9
es.EnsureCapacity(ensureLargeLen)
assert.Less(t, generateTest${structName}().Len(), ensureLargeLen)
assert.Less(t, generateTest{{ .structName }}().Len(), ensureLargeLen)
assert.Equal(t, ensureLargeLen, cap(*es.orig))
assert.Equal(t, generateTest${structName}(), es)
assert.Equal(t, generateTest{{ .structName }}(), es)
}
func Test${structName}_MoveAndAppendTo(t *testing.T) {
func Test{{ .structName }}_MoveAndAppendTo(t *testing.T) {
// Test MoveAndAppendTo to empty
expectedSlice := generateTest${structName}()
dest := New${structName}()
src := generateTest${structName}()
expectedSlice := generateTest{{ .structName }}()
dest := New{{ .structName }}()
src := generateTest{{ .structName }}()
src.MoveAndAppendTo(dest)
assert.Equal(t, generateTest${structName}(), dest)
assert.Equal(t, generateTest{{ .structName }}(), dest)
assert.Equal(t, 0, src.Len())
assert.Equal(t, expectedSlice.Len(), dest.Len())
// Test MoveAndAppendTo empty slice
src.MoveAndAppendTo(dest)
assert.Equal(t, generateTest${structName}(), dest)
assert.Equal(t, generateTest{{ .structName }}(), dest)
assert.Equal(t, 0, src.Len())
assert.Equal(t, expectedSlice.Len(), dest.Len())
// Test MoveAndAppendTo not empty slice
generateTest${structName}().MoveAndAppendTo(dest)
generateTest{{ .structName }}().MoveAndAppendTo(dest)
assert.Equal(t, 2*expectedSlice.Len(), dest.Len())
for i := 0; i < expectedSlice.Len(); i++ {
assert.Equal(t, expectedSlice.At(i), dest.At(i))
@ -195,94 +236,53 @@ func Test${structName}_MoveAndAppendTo(t *testing.T) {
}
}
func Test${structName}_RemoveIf(t *testing.T) {
func Test{{ .structName }}_RemoveIf(t *testing.T) {
// Test RemoveIf on empty slice
emptySlice := New${structName}()
emptySlice.RemoveIf(func(el ${elementName}) bool {
emptySlice := New{{ .structName }}()
emptySlice.RemoveIf(func(el {{ .elementName }}) bool {
t.Fail()
return false
})
// Test RemoveIf
filtered := generateTest${structName}()
filtered := generateTest{{ .structName }}()
pos := 0
filtered.RemoveIf(func(el ${elementName}) bool {
filtered.RemoveIf(func(el {{ .elementName }}) bool {
pos++
return pos%3 == 0
})
assert.Equal(t, 5, filtered.Len())
}`
const slicePtrTemplate = `// CopyTo copies all elements from the current slice overriding the destination.
func (es ${structName}) CopyTo(dest ${structName}) {
srcLen := es.Len()
destCap := cap(*dest.orig)
if srcLen <= destCap {
(*dest.orig) = (*dest.orig)[:srcLen:destCap]
for i := range *es.orig {
new${elementName}((*es.orig)[i]).CopyTo(new${elementName}((*dest.orig)[i]))
}
return
}
origs := make([]${originName}, srcLen)
wrappers := make([]*${originName}, srcLen)
for i := range *es.orig {
wrappers[i] = &origs[i]
new${elementName}((*es.orig)[i]).CopyTo(new${elementName}(wrappers[i]))
}
*dest.orig = wrappers
}
// Sort sorts the ${elementName} elements within ${structName} given the
// provided less function so that two instances of ${structName}
// can be compared.
func (es ${structName}) Sort(less func(a, b ${elementName}) bool) {
sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) })
}`
// TODO: Use assert.Less once https://github.com/stretchr/testify/pull/1339 is merged.
const slicePtrTestTemplate = `func Test${structName}_Sort(t *testing.T) {
es := generateTest${structName}()
es.Sort(func(a, b ${elementName}) bool {
{{ if eq .type "sliceOfPtrs" -}}
func Test{{ .structName }}_Sort(t *testing.T) {
es := generateTest{{ .structName }}()
es.Sort(func(a, b {{ .elementName }}) bool {
return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig))
})
for i := 1; i < es.Len(); i++ {
assert.True(t, uintptr(unsafe.Pointer(es.At(i-1).orig)) < uintptr(unsafe.Pointer(es.At(i).orig)))
}
es.Sort(func(a, b ${elementName}) bool {
es.Sort(func(a, b {{ .elementName }}) bool {
return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig))
})
for i := 1; i < es.Len(); i++ {
assert.True(t, uintptr(unsafe.Pointer(es.At(i-1).orig)) > uintptr(unsafe.Pointer(es.At(i).orig)))
}
}`
}
{{- end }}`
const sliceValueTemplate = `// CopyTo copies all elements from the current slice overriding the destination.
func (es ${structName}) CopyTo(dest ${structName}) {
srcLen := es.Len()
destCap := cap(*dest.orig)
if srcLen <= destCap {
(*dest.orig) = (*dest.orig)[:srcLen:destCap]
} else {
(*dest.orig) = make([]${originName}, srcLen)
}
for i := range *es.orig {
new${elementName}(&(*es.orig)[i]).CopyTo(new${elementName}(&(*dest.orig)[i]))
}
}`
const commonSliceGenerateTest = `func generateTest${structName}() ${structName} {
es := New${structName}()
fillTest${structName}(es)
const sliceGenerateTest = `func generateTest{{ .structName }}() {{ .structName }} {
es := New{{ .structName }}()
fillTest{{ .structName }}(es)
return es
}
func fillTest${structName}(es ${structName}) {
*es.orig = make([]${originElementType}, 7)
func fillTest{{ .structName }}(es {{ .structName }}) {
*es.orig = make([]{{ .originElementType }}, 7)
for i := 0; i < 7; i++ {
(*es.orig)[i] = ${emptyOriginElement}
fillTest${elementName}(${newElement})
(*es.orig)[i] = {{ .emptyOriginElement }}
fillTest{{ .elementName }}({{ .newElement }})
}
}`
@ -307,37 +307,35 @@ func (ss *sliceOfPtrs) getPackageName() string {
}
func (ss *sliceOfPtrs) generateStruct(sb *bytes.Buffer) {
sb.WriteString(os.Expand(commonSliceTemplate, ss.templateFields()) + newLine + newLine)
sb.WriteString(os.Expand(slicePtrTemplate, ss.templateFields()))
t := template.Must(template.New("sliceTemplate").Parse(sliceTemplate))
if err := t.Execute(sb, ss.templateFields()); err != nil {
panic(err)
}
}
func (ss *sliceOfPtrs) generateTests(sb *bytes.Buffer) {
sb.WriteString(os.Expand(commonSliceTestTemplate, ss.templateFields()) + newLine + newLine)
sb.WriteString(os.Expand(slicePtrTestTemplate, ss.templateFields()))
t := template.Must(template.New("sliceTestTemplate").Parse(sliceTestTemplate))
if err := t.Execute(sb, ss.templateFields()); err != nil {
panic(err)
}
}
func (ss *sliceOfPtrs) generateTestValueHelpers(sb *bytes.Buffer) {
sb.WriteString(os.Expand(commonSliceGenerateTest, ss.templateFields()))
t := template.Must(template.New("sliceGenerateTest").Parse(sliceGenerateTest))
if err := t.Execute(sb, ss.templateFields()); err != nil {
panic(err)
}
}
func (ss *sliceOfPtrs) templateFields() func(name string) string {
return func(name string) string {
switch name {
case "structName":
return ss.structName
case "elementName":
return ss.element.structName
case "originName":
return ss.element.originFullName
case "originElementType":
return "*" + ss.element.originFullName
case "emptyOriginElement":
return "&" + ss.element.originFullName + "{}"
case "newElement":
return "new" + ss.element.structName + "((*es.orig)[i])"
default:
panic(name)
}
func (ss *sliceOfPtrs) templateFields() map[string]any {
return map[string]any{
"type": "sliceOfPtrs",
"structName": ss.structName,
"elementName": ss.element.structName,
"originName": ss.element.originFullName,
"originElementType": "*" + ss.element.originFullName,
"emptyOriginElement": "&" + ss.element.originFullName + "{}",
"newElement": "new" + ss.element.structName + "((*es.orig)[i])",
}
}
@ -361,36 +359,35 @@ func (ss *sliceOfValues) getPackageName() string {
}
func (ss *sliceOfValues) generateStruct(sb *bytes.Buffer) {
sb.WriteString(os.Expand(commonSliceTemplate, ss.templateFields()) + newLine + newLine)
sb.WriteString(os.Expand(sliceValueTemplate, ss.templateFields()))
t := template.Must(template.New("sliceTemplate").Parse(sliceTemplate))
if err := t.Execute(sb, ss.templateFields()); err != nil {
panic(err)
}
}
func (ss *sliceOfValues) generateTests(sb *bytes.Buffer) {
sb.WriteString(os.Expand(commonSliceTestTemplate, ss.templateFields()))
t := template.Must(template.New("sliceTestTemplate").Parse(sliceTestTemplate))
if err := t.Execute(sb, ss.templateFields()); err != nil {
panic(err)
}
}
func (ss *sliceOfValues) generateTestValueHelpers(sb *bytes.Buffer) {
sb.WriteString(os.Expand(commonSliceGenerateTest, ss.templateFields()))
t := template.Must(template.New("sliceGenerateTest").Parse(sliceGenerateTest))
if err := t.Execute(sb, ss.templateFields()); err != nil {
panic(err)
}
}
func (ss *sliceOfValues) templateFields() func(name string) string {
return func(name string) string {
switch name {
case "structName":
return ss.structName
case "elementName":
return ss.element.structName
case "originName":
return ss.element.originFullName
case "originElementType":
return ss.element.originFullName
case "emptyOriginElement":
return ss.element.originFullName + "{}"
case "newElement":
return "new" + ss.element.structName + "(&(*es.orig)[i])"
default:
panic(name)
}
func (ss *sliceOfValues) templateFields() map[string]any {
return map[string]any{
"type": "sliceOfValues",
"structName": ss.structName,
"elementName": ss.element.structName,
"originName": ss.element.originFullName,
"originElementType": ss.element.originFullName,
"emptyOriginElement": ss.element.originFullName + "{}",
"newElement": "new" + ss.element.structName + "(&(*es.orig)[i])",
}
}

View File

@ -16,93 +16,116 @@ package internal // import "go.opentelemetry.io/collector/pdata/internal/cmd/pda
import (
"bytes"
"os"
"strings"
"text/template"
)
const messageValueTemplate = `${description}
const messageValueTemplate = `{{ .description }}
//
// This is a reference type, if passed by value and callee modifies it the
// caller will see the modification.
//
// Must use New${structName} function to create new instances.
// Must use New{{ .structName }} function to create new instances.
// Important: zero-initialized instance is not valid for use.
${typeDeclaration}
{{- if .isCommon }}
type {{ .structName }} internal.{{ .structName }}
{{- else }}
type {{ .structName }} struct {
orig *{{ .originName }}
}
{{- end }}
func new${structName}(orig *${originName}) ${structName} {
return ${newFuncValue}
func new{{ .structName }}(orig *{{ .originName }}) {{ .structName }} {
{{- if .isCommon }}
return {{ .structName }}(internal.New{{ .structName }}(orig))
{{- else }}
return {{ .structName }}{orig}
{{- end }}
}
// New${structName} creates a new empty ${structName}.
// New{{ .structName }} creates a new empty {{ .structName }}.
//
// This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice,
// OR directly access the member if this is embedded in another struct.
func New${structName}() ${structName} {
return new${structName}(&${originName}{})
func New{{ .structName }}() {{ .structName }} {
return new{{ .structName }}(&{{ .originName }}{})
}
// MoveTo moves all properties from the current struct overriding the destination and
// resetting the current instance to its zero value
func (ms ${structName}) MoveTo(dest ${structName}) {
*dest.${origAccessor} = *ms.${origAccessor}
*ms.${origAccessor} = ${originName}{}
}`
const messageValueGetOrigTemplate = `func (ms ${structName}) getOrig() *${originName} {
return internal.GetOrig${structName}(internal.${structName}(ms))
}`
const messageValueCopyToHeaderTemplate = `// CopyTo copies all properties from the current struct overriding the destination.
func (ms ${structName}) CopyTo(dest ${structName}) {`
const messageValueCopyToFooterTemplate = `}`
const messageValueTestTemplate = `
func Test${structName}_MoveTo(t *testing.T) {
ms := ${generateTestData}
dest := New${structName}()
ms.MoveTo(dest)
assert.Equal(t, New${structName}(), ms)
assert.Equal(t, ${generateTestData}, dest)
func (ms {{ .structName }}) MoveTo(dest {{ .structName }}) {
*dest.{{ .origAccessor }} = *ms.{{ .origAccessor }}
*ms.{{ .origAccessor }} = {{ .originName }}{}
}
func Test${structName}_CopyTo(t *testing.T) {
ms := New${structName}()
orig := New${structName}()
orig.CopyTo(ms)
assert.Equal(t, orig, ms)
orig = ${generateTestData}
orig.CopyTo(ms)
assert.Equal(t, orig, ms)
{{ if .isCommon -}}
func (ms {{ .structName }}) getOrig() *{{ .originName }} {
return internal.GetOrig{{ .structName }}(internal.{{ .structName }}(ms))
}
{{- end }}
{{ range .fields -}}
{{ .GenerateAccessors $.messageStruct }}
{{ end }}
// CopyTo copies all properties from the current struct overriding the destination.
func (ms {{ .structName }}) CopyTo(dest {{ .structName }}) {
{{- range .fields }}
{{ .GenerateCopyToValue $.messageStruct }}
{{- end }}
}`
const messageValueGenerateTestTemplate = `func generateTest${structName}() ${structName} {
tv := New${structName}()
fillTest${structName}(tv)
return tv
}`
const messageValueTestTemplate = `
func Test{{ .structName }}_MoveTo(t *testing.T) {
ms := {{ .generateTestData }}
dest := New{{ .structName }}()
ms.MoveTo(dest)
assert.Equal(t, New{{ .structName }}(), ms)
assert.Equal(t, {{ .generateTestData }}, dest)
}
const messageValueGenerateTestTemplateCommon = `func GenerateTest${structName}() ${structName} {
orig := ${originName}{}
tv := New${structName}(&orig)
FillTest${structName}(tv)
func Test{{ .structName }}_CopyTo(t *testing.T) {
ms := New{{ .structName }}()
orig := New{{ .structName }}()
orig.CopyTo(ms)
assert.Equal(t, orig, ms)
orig = {{ .generateTestData }}
orig.CopyTo(ms)
assert.Equal(t, orig, ms)
}
{{ range .fields }}
{{ .GenerateAccessorsTest $.messageStruct }}
{{ end }}`
const messageValueGenerateTestTemplate = `func {{ upperIfInternal "g" }}enerateTest{{ .structName }}() {{ .structName }} {
{{- if .isCommon }}
orig := {{ .originName }}{}
{{- end }}
tv := New{{ .structName }}({{ if .isCommon }}&orig{{ end }})
{{ upperIfInternal "f" }}illTest{{ .structName }}(tv)
return tv
}
func {{ upperIfInternal "f" }}illTest{{ .structName }}(tv {{ .structName }}) {
{{- range .fields }}
{{ .GenerateSetWithTestValue $.messageStruct }}
{{- end }}
}`
const messageValueAliasTemplate = `
type ${structName} struct {
orig *${originName}
type {{ .structName }} struct {
orig *{{ .originName }}
}
func GetOrig${structName}(ms ${structName}) *${originName} {
func GetOrig{{ .structName }}(ms {{ .structName }}) *{{ .originName }} {
return ms.orig
}
func New${structName}(orig *${originName}) ${structName} {
return ${structName}{orig: orig}
func New{{ .structName }}(orig *{{ .originName }}) {{ .structName }} {
return {{ .structName }}{orig: orig}
}`
const newLine = "\n"
type baseStruct interface {
getName() string
getPackageName() string
@ -131,96 +154,56 @@ func (ms *messageValueStruct) getPackageName() string {
}
func (ms *messageValueStruct) generateStruct(sb *bytes.Buffer) {
sb.WriteString(os.Expand(messageValueTemplate, ms.templateFields()))
if usedByOtherDataTypes(ms.packageName) {
sb.WriteString(newLine + newLine)
sb.WriteString(os.Expand(messageValueGetOrigTemplate, ms.templateFields()))
t := template.Must(template.New("messageValueTemplate").Parse(messageValueTemplate))
if err := t.Execute(sb, ms.templateFields()); err != nil {
panic(err)
}
// Write accessors for the struct
for _, f := range ms.fields {
sb.WriteString(newLine + newLine)
f.generateAccessors(ms, sb)
}
sb.WriteString(newLine + newLine)
sb.WriteString(os.Expand(messageValueCopyToHeaderTemplate, ms.templateFields()))
// Write accessors CopyTo for the struct
for _, f := range ms.fields {
sb.WriteString(newLine)
f.generateCopyToValue(ms, sb)
}
sb.WriteString(newLine)
sb.WriteString(messageValueCopyToFooterTemplate)
}
func (ms *messageValueStruct) generateTests(sb *bytes.Buffer) {
sb.WriteString(os.Expand(messageValueTestTemplate, ms.templateFields()))
// Write accessors tests for the struct
for _, f := range ms.fields {
sb.WriteString(newLine + newLine)
f.generateAccessorsTest(ms, sb)
t := template.Must(template.New("messageValueTestTemplate").Parse(messageValueTestTemplate))
if err := t.Execute(sb, ms.templateFields()); err != nil {
panic(err)
}
}
func (ms *messageValueStruct) generateTestValueHelpers(sb *bytes.Buffer) {
// Write generateTest func for the struct
template := messageValueGenerateTestTemplate
if usedByOtherDataTypes(ms.packageName) {
template = messageValueGenerateTestTemplateCommon
funcs := template.FuncMap{
"upperIfInternal": func(in string) string {
if usedByOtherDataTypes(ms.packageName) {
return strings.ToUpper(in)
}
return in
},
}
sb.WriteString(os.Expand(template, ms.templateFields()))
// Write fillTest func for the struct
sb.WriteString(newLine + newLine + "func ")
if usedByOtherDataTypes(ms.packageName) {
sb.WriteString("FillTest")
} else {
sb.WriteString("fillTest")
t := template.Must(template.New("messageValueGenerateTestTemplate").Funcs(funcs).Parse(messageValueGenerateTestTemplate))
if err := t.Execute(sb, ms.templateFields()); err != nil {
panic(err)
}
sb.WriteString(ms.structName + "(tv " + ms.structName + ") {")
for _, f := range ms.fields {
sb.WriteString(newLine)
f.generateSetWithTestValue(ms, sb)
}
sb.WriteString(newLine + "}" + newLine)
}
func (ms *messageValueStruct) generateInternal(sb *bytes.Buffer) {
sb.WriteString(os.Expand(messageValueAliasTemplate, ms.templateFields()))
sb.WriteString(newLine + newLine)
t := template.Must(template.New("messageValueAliasTemplate").Parse(messageValueAliasTemplate))
if err := t.Execute(sb, ms.templateFields()); err != nil {
panic(err)
}
}
func (ms *messageValueStruct) templateFields() func(name string) string {
return func(name string) string {
switch name {
case "structName":
return ms.structName
case "originName":
return ms.originFullName
case "generateTestData":
func (ms *messageValueStruct) templateFields() map[string]any {
return map[string]any{
"messageStruct": ms,
"fields": ms.fields,
"structName": ms.structName,
"originName": ms.originFullName,
"generateTestData": func() string {
if usedByOtherDataTypes(ms.packageName) {
return ms.structName + "(internal.GenerateTest" + ms.structName + "())"
}
return "generateTest" + ms.structName + "()"
case "description":
return ms.description
case "typeDeclaration":
if usedByOtherDataTypes(ms.packageName) {
return "type " + ms.structName + " internal." + ms.structName
}
return "type " + ms.structName + " struct {\n\torig *" + ms.originFullName + "\n}"
case "newFuncValue":
if usedByOtherDataTypes(ms.packageName) {
return ms.structName + "(internal.New" + ms.structName + "(orig))"
}
return ms.structName + "{orig}"
case "origAccessor":
return origAccessor(ms)
default:
panic(name)
}
}(),
"description": ms.description,
"isCommon": usedByOtherDataTypes(ms.packageName),
"origAccessor": origAccessor(ms),
}
}

View File

@ -59,6 +59,8 @@ type Package struct {
structs []baseStruct
}
const newLine = "\n"
// GenerateFiles generates files with the configured data structures for this Package.
func (p *Package) GenerateFiles() error {
for _, s := range p.structs {

View File

@ -16,136 +16,136 @@ package internal // import "go.opentelemetry.io/collector/pdata/internal/cmd/pda
import (
"bytes"
"os"
"strings"
"text/template"
)
const primitiveSliceTemplate = `// ${structName} represents a []${itemType} slice.
// The instance of ${structName} can be assigned to multiple objects since it's immutable.
const primitiveSliceTemplate = `// {{ .structName }} represents a []{{ .itemType }} slice.
// The instance of {{ .structName }} can be assigned to multiple objects since it's immutable.
//
// Must use New${structName} function to create new instances.
// Must use New{{ .structName }} function to create new instances.
// Important: zero-initialized instance is not valid for use.
type ${structName} internal.${structName}
type {{ .structName }} internal.{{ .structName }}
func (ms ${structName}) getOrig() *[]${itemType} {
return internal.GetOrig${structName}(internal.${structName}(ms))
func (ms {{ .structName }}) getOrig() *[]{{ .itemType }} {
return internal.GetOrig{{ .structName }}(internal.{{ .structName }}(ms))
}
// New${structName} creates a new empty ${structName}.
func New${structName}() ${structName} {
orig := []${itemType}(nil)
return ${structName}(internal.New${structName}(&orig))
// New{{ .structName }} creates a new empty {{ .structName }}.
func New{{ .structName }}() {{ .structName }} {
orig := []{{ .itemType }}(nil)
return {{ .structName }}(internal.New{{ .structName }}(&orig))
}
// AsRaw returns a copy of the []${itemType} slice.
func (ms ${structName}) AsRaw() []${itemType} {
return copy${structName}(nil, *ms.getOrig())
// AsRaw returns a copy of the []{{ .itemType }} slice.
func (ms {{ .structName }}) AsRaw() []{{ .itemType }} {
return copy{{ .structName }}(nil, *ms.getOrig())
}
// FromRaw copies raw []${itemType} into the slice ${structName}.
func (ms ${structName}) FromRaw(val []${itemType}) {
*ms.getOrig() = copy${structName}(*ms.getOrig(), val)
// FromRaw copies raw []{{ .itemType }} into the slice {{ .structName }}.
func (ms {{ .structName }}) FromRaw(val []{{ .itemType }}) {
*ms.getOrig() = copy{{ .structName }}(*ms.getOrig(), val)
}
// Len returns length of the []${itemType} slice value.
// Equivalent of len(${lowerStructName}).
func (ms ${structName}) Len() int {
// Len returns length of the []{{ .itemType }} slice value.
// Equivalent of len({{ .lowerStructName }}).
func (ms {{ .structName }}) Len() int {
return len(*ms.getOrig())
}
// At returns an item from particular index.
// Equivalent of ${lowerStructName}[i].
func (ms ${structName}) At(i int) ${itemType} {
// Equivalent of {{ .lowerStructName }}[i].
func (ms {{ .structName }}) At(i int) {{ .itemType }} {
return (*ms.getOrig())[i]
}
// SetAt sets ${itemType} item at particular index.
// Equivalent of ${lowerStructName}[i] = val
func (ms ${structName}) SetAt(i int, val ${itemType}) {
// SetAt sets {{ .itemType }} item at particular index.
// Equivalent of {{ .lowerStructName }}[i] = val
func (ms {{ .structName }}) SetAt(i int, val {{ .itemType }}) {
(*ms.getOrig())[i] = val
}
// EnsureCapacity ensures ${structName} has at least the specified capacity.
// EnsureCapacity ensures {{ .structName }} has at least the specified capacity.
// 1. If the newCap <= cap, then is no change in capacity.
// 2. If the newCap > cap, then the slice capacity will be expanded to the provided value which will be equivalent of:
// buf := make([]${itemType}, len(${lowerStructName}), newCap)
// copy(buf, ${lowerStructName})
// ${lowerStructName} = buf
func (ms ${structName}) EnsureCapacity(newCap int) {
// buf := make([]{{ .itemType }}, len({{ .lowerStructName }}), newCap)
// copy(buf, {{ .lowerStructName }})
// {{ .lowerStructName }} = buf
func (ms {{ .structName }}) EnsureCapacity(newCap int) {
oldCap := cap(*ms.getOrig())
if newCap <= oldCap {
return
}
newOrig := make([]${itemType}, len(*ms.getOrig()), newCap)
newOrig := make([]{{ .itemType }}, len(*ms.getOrig()), newCap)
copy(newOrig, *ms.getOrig())
*ms.getOrig() = newOrig
}
// Append appends extra elements to ${structName}.
// Equivalent of ${lowerStructName} = append(${lowerStructName}, elms...)
func (ms ${structName}) Append(elms ...${itemType}) {
// Append appends extra elements to {{ .structName }}.
// Equivalent of {{ .lowerStructName }} = append({{ .lowerStructName }}, elms...)
func (ms {{ .structName }}) Append(elms ...{{ .itemType }}) {
*ms.getOrig() = append(*ms.getOrig(), elms...)
}
// MoveTo moves all elements from the current slice overriding the destination and
// resetting the current instance to its zero value.
func (ms ${structName}) MoveTo(dest ${structName}) {
func (ms {{ .structName }}) MoveTo(dest {{ .structName }}) {
*dest.getOrig() = *ms.getOrig()
*ms.getOrig() = nil
}
// CopyTo copies all elements from the current slice overriding the destination.
func (ms ${structName}) CopyTo(dest ${structName}) {
*dest.getOrig() = copy${structName}(*dest.getOrig(), *ms.getOrig())
func (ms {{ .structName }}) CopyTo(dest {{ .structName }}) {
*dest.getOrig() = copy{{ .structName }}(*dest.getOrig(), *ms.getOrig())
}
func copy${structName}(dst, src []${itemType}) []${itemType} {
func copy{{ .structName }}(dst, src []{{ .itemType }}) []{{ .itemType }} {
dst = dst[:0]
return append(dst, src...)
}`
const immutableSliceTestTemplate = `func TestNew${structName}(t *testing.T) {
ms := New${structName}()
const immutableSliceTestTemplate = `func TestNew{{ .structName }}(t *testing.T) {
ms := New{{ .structName }}()
assert.Equal(t, 0, ms.Len())
ms.FromRaw([]${itemType}{1, 2, 3})
ms.FromRaw([]{{ .itemType }}{1, 2, 3})
assert.Equal(t, 3, ms.Len())
assert.Equal(t, []${itemType}{1, 2, 3}, ms.AsRaw())
ms.SetAt(1, ${itemType}(5))
assert.Equal(t, []${itemType}{1, 5, 3}, ms.AsRaw())
ms.FromRaw([]${itemType}{3})
assert.Equal(t, []{{ .itemType }}{1, 2, 3}, ms.AsRaw())
ms.SetAt(1, {{ .itemType }}(5))
assert.Equal(t, []{{ .itemType }}{1, 5, 3}, ms.AsRaw())
ms.FromRaw([]{{ .itemType }}{3})
assert.Equal(t, 1, ms.Len())
assert.Equal(t, ${itemType}(3), ms.At(0))
assert.Equal(t, {{ .itemType }}(3), ms.At(0))
cp := New${structName}()
cp := New{{ .structName }}()
ms.CopyTo(cp)
ms.SetAt(0, ${itemType}(2))
assert.Equal(t, ${itemType}(2), ms.At(0))
assert.Equal(t, ${itemType}(3), cp.At(0))
ms.SetAt(0, {{ .itemType }}(2))
assert.Equal(t, {{ .itemType }}(2), ms.At(0))
assert.Equal(t, {{ .itemType }}(3), cp.At(0))
ms.CopyTo(cp)
assert.Equal(t, ${itemType}(2), cp.At(0))
assert.Equal(t, {{ .itemType }}(2), cp.At(0))
mv := New${structName}()
mv := New{{ .structName }}()
ms.MoveTo(mv)
assert.Equal(t, 0, ms.Len())
assert.Equal(t, 1, mv.Len())
assert.Equal(t, ${itemType}(2), mv.At(0))
ms.FromRaw([]${itemType}{1, 2, 3})
assert.Equal(t, {{ .itemType }}(2), mv.At(0))
ms.FromRaw([]{{ .itemType }}{1, 2, 3})
ms.MoveTo(mv)
assert.Equal(t, 3, mv.Len())
assert.Equal(t, ${itemType}(1), mv.At(0))
assert.Equal(t, {{ .itemType }}(1), mv.At(0))
}
func Test${structName}Append(t *testing.T) {
ms := New${structName}()
ms.FromRaw([]${itemType}{1, 2, 3})
func Test{{ .structName }}Append(t *testing.T) {
ms := New{{ .structName }}()
ms.FromRaw([]{{ .itemType }}{1, 2, 3})
ms.Append(4, 5)
assert.Equal(t, 5, ms.Len())
assert.Equal(t, ${itemType}(5), ms.At(4))
assert.Equal(t, {{ .itemType }}(5), ms.At(4))
}
func Test${structName}EnsureCapacity(t *testing.T) {
ms := New${structName}()
func Test{{ .structName }}EnsureCapacity(t *testing.T) {
ms := New{{ .structName }}()
ms.EnsureCapacity(4)
assert.Equal(t, 4, cap(*ms.getOrig()))
ms.EnsureCapacity(2)
@ -153,16 +153,16 @@ func Test${structName}EnsureCapacity(t *testing.T) {
}`
const primitiveSliceInternalTemplate = `
type ${structName} struct {
orig *[]${itemType}
type {{ .structName }} struct {
orig *[]{{ .itemType }}
}
func GetOrig${structName}(ms ${structName}) *[]${itemType} {
func GetOrig{{ .structName }}(ms {{ .structName }}) *[]{{ .itemType }} {
return ms.orig
}
func New${structName}(orig *[]${itemType}) ${structName} {
return ${structName}{orig: orig}
func New{{ .structName }}(orig *[]{{ .itemType }}) {{ .structName }} {
return {{ .structName }}{orig: orig}
}`
// primitiveSliceStruct generates a struct for a slice of primitive value elements. The structs are always generated
@ -182,44 +182,32 @@ func (iss *primitiveSliceStruct) getPackageName() string {
}
func (iss *primitiveSliceStruct) generateStruct(sb *bytes.Buffer) {
sb.WriteString(os.Expand(primitiveSliceTemplate, func(name string) string {
switch name {
case "structName":
return iss.structName
case "lowerStructName":
return strings.ToLower(iss.structName[:1]) + iss.structName[1:]
case "itemType":
return iss.itemType
default:
panic(name)
}
}))
t := template.Must(template.New("primitiveSliceTemplate").Parse(primitiveSliceTemplate))
if err := t.Execute(sb, iss.templateFields()); err != nil {
panic(err)
}
}
func (iss *primitiveSliceStruct) generateTests(sb *bytes.Buffer) {
sb.WriteString(os.Expand(immutableSliceTestTemplate, func(name string) string {
switch name {
case "structName":
return iss.structName
case "itemType":
return iss.itemType
default:
panic(name)
}
}))
t := template.Must(template.New("immutableSliceTestTemplate").Parse(immutableSliceTestTemplate))
if err := t.Execute(sb, iss.templateFields()); err != nil {
panic(err)
}
}
func (iss *primitiveSliceStruct) generateTestValueHelpers(*bytes.Buffer) {}
func (iss *primitiveSliceStruct) generateInternal(sb *bytes.Buffer) {
sb.WriteString(os.Expand(primitiveSliceInternalTemplate, func(name string) string {
switch name {
case "structName":
return iss.structName
case "itemType":
return iss.itemType
default:
panic(name)
}
}))
t := template.Must(template.New("primitiveSliceInternalTemplate").Parse(primitiveSliceInternalTemplate))
if err := t.Execute(sb, iss.templateFields()); err != nil {
panic(err)
}
}
func (iss *primitiveSliceStruct) templateFields() map[string]any {
return map[string]any{
"structName": iss.structName,
"itemType": iss.itemType,
"lowerStructName": strings.ToLower(iss.structName[:1]) + iss.structName[1:],
}
}

View File

@ -133,7 +133,6 @@ func (es ExemplarSlice) CopyTo(dest ExemplarSlice) {
} else {
(*dest.orig) = make([]otlpmetrics.Exemplar, srcLen)
}
for i := range *es.orig {
newExemplar(&(*es.orig)[i]).CopyTo(newExemplar(&(*dest.orig)[i]))
}