diff --git a/pdata/internal/cmd/pdatagen/internal/base_slices.go b/pdata/internal/cmd/pdatagen/internal/base_slices.go index 21646d92bc1..24c648de9f2 100644 --- a/pdata/internal/cmd/pdatagen/internal/base_slices.go +++ b/pdata/internal/cmd/pdatagen/internal/base_slices.go @@ -5,298 +5,8 @@ package internal // import "go.opentelemetry.io/collector/pdata/internal/cmd/pda import ( "bytes" - "text/template" ) -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. -// Important: zero-initialized instance is not valid for use. -type {{ .structName }} struct { - orig *[]{{ .originElementType }} - state *internal.State -} - -func new{{ .structName }}(orig *[]{{ .originElementType }}, state *internal.State) {{ .structName }} { - return {{ .structName }}{orig: orig, state: state} -} - -// New{{ .structName }} creates a {{ .structName }} with 0 elements. -// Can use "EnsureCapacity" to initialize with a given capacity. -func New{{ .structName }}() {{ .structName }} { - orig := []{{ .originElementType }}(nil) - state := internal.StateMutable - return new{{ .structName }}(&orig, &state) -} - -// Len returns the number of elements in the slice. -// -// Returns "0" for a newly instance created with "New{{ .structName }}()". -func (es {{ .structName }}) Len() int { - return len(*es.orig) -} - -// At returns the element at the given index. -// -// This function is used mostly for iterating over all the values in the slice: -// for i := 0; i < es.Len(); i++ { -// e := es.At(i) -// ... // Do something with the element -// } -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 }}() -// 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) { - es.state.AssertMutable() - oldCap := cap(*es.orig) - if newCap <= oldCap { - return - } - - 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.state.AssertMutable() - *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 }}) { - es.state.AssertMutable() - dest.state.AssertMutable() - if *dest.orig == nil { - // We can simply move the entire vector and avoid any allocations. - *dest.orig = *es.orig - } else { - *dest.orig = append(*dest.orig, *es.orig...) - } - *es.orig = nil -} - -// 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) { - es.state.AssertMutable() - newLen := 0 - for i := 0; i < len(*es.orig); i++ { - if f(es.At(i)) { - continue - } - if newLen == i { - // Nothing to move, element is at the right place. - newLen++ - continue - } - (*es.orig)[newLen] = (*es.orig)[i] - newLen++ - } - *es.orig = (*es.orig)[:newLen] -} - - -// CopyTo copies all elements from the current slice overriding the destination. -func (es {{ .structName }}) CopyTo(dest {{ .structName }}) { - dest.state.AssertMutable() - 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], es.state).CopyTo(new{{ .elementName }}((*dest.orig)[i], dest.state)) - } - return - } - origs := make([]{{ .originName }}, srcLen) - wrappers := make([]*{{ .originName }}, srcLen) - for i := range *es.orig { - wrappers[i] = &origs[i] - new{{ .elementName }}((*es.orig)[i], es.state).CopyTo(new{{ .elementName }}(wrappers[i], dest.state)) - } - *dest.orig = wrappers - - {{- else }} - } else { - (*dest.orig) = make([]{{ .originElementType }}, srcLen) - } - for i := range *es.orig { - {{ .newElement }}.CopyTo(new{{ .elementName }}(&(*dest.orig)[i], dest.state)) - } - {{- 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) { - es.state.AssertMutable() - 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()) - state := internal.StateMutable - es = new{{ .structName }}(&[]{{ .originElementType }}{}, &state) - assert.Equal(t, 0, es.Len()) - - 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) - assert.Equal(t, testVal, es.At(i)) - } - assert.Equal(t, 7, es.Len()) -} - -func Test{{ .structName }}ReadOnly(t *testing.T) { - sharedState := internal.StateReadOnly - es := new{{ .structName }}(&[]{{ .originElementType }}{}, &sharedState) - assert.Equal(t, 0, es.Len()) - assert.Panics(t, func() { es.AppendEmpty() }) - assert.Panics(t, func() { es.EnsureCapacity(2) }) - es2 := New{{ .structName }}() - es.CopyTo(es2) - assert.Panics(t, func() { es2.CopyTo(es) }) - assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) - assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) -} - -func Test{{ .structName }}_CopyTo(t *testing.T) { - dest := New{{ .structName }}() - // Test CopyTo to empty - New{{ .structName }}().CopyTo(dest) - assert.Equal(t, New{{ .structName }}(), dest) - - // Test CopyTo larger slice - 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) -} - -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) - - // Test ensure larger capacity - const ensureLargeLen = 9 - es.EnsureCapacity(ensureLargeLen) - assert.Less(t, generateTest{{ .structName }}().Len(), ensureLargeLen) - assert.Equal(t, ensureLargeLen, cap(*es.orig)) - assert.Equal(t, generateTest{{ .structName }}(), es) -} - -func Test{{ .structName }}_MoveAndAppendTo(t *testing.T) { - // Test MoveAndAppendTo to empty - expectedSlice := generateTest{{ .structName }}() - dest := New{{ .structName }}() - src := generateTest{{ .structName }}() - src.MoveAndAppendTo(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, 0, src.Len()) - assert.Equal(t, expectedSlice.Len(), dest.Len()) - - // Test MoveAndAppendTo not empty slice - 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)) - assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) - } -} - -func Test{{ .structName }}_RemoveIf(t *testing.T) { - // Test RemoveIf on empty slice - emptySlice := New{{ .structName }}() - emptySlice.RemoveIf(func(el {{ .elementName }}) bool { - t.Fail() - return false - }) - - // Test RemoveIf - filtered := generateTest{{ .structName }}() - pos := 0 - filtered.RemoveIf(func(el {{ .elementName }}) bool { - pos++ - return pos%3 == 0 - }) - assert.Equal(t, 5, filtered.Len()) -} - -{{ 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.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) - } - 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.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) - } -} -{{- end }}` - -const sliceGenerateTest = `func generateTest{{ .structName }}() {{ .structName }} { - es := New{{ .structName }}() - fillTest{{ .structName }}(es) - return es -} - -func fillTest{{ .structName }}(es {{ .structName }}) { - *es.orig = make([]{{ .originElementType }}, 7) - for i := 0; i < 7; i++ { - (*es.orig)[i] = {{ .emptyOriginElement }} - fillTest{{ .elementName }}({{ .newElement }}) - } -}` - type baseSlice interface { getName() string getPackageName() string @@ -317,28 +27,23 @@ func (ss *sliceOfPtrs) getPackageName() string { return ss.packageName } -func (ss *sliceOfPtrs) generateStruct(sb *bytes.Buffer) { - 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) { - t := template.Must(template.New("sliceTestTemplate").Parse(sliceTestTemplate)) - if err := t.Execute(sb, ss.templateFields()); err != nil { +func (ss *sliceOfPtrs) generate(packageInfo *PackageInfo) []byte { + var sb bytes.Buffer + if err := sliceTemplate.Execute(&sb, ss.templateFields(packageInfo)); err != nil { panic(err) } + return sb.Bytes() } -func (ss *sliceOfPtrs) generateTestValueHelpers(sb *bytes.Buffer) { - t := template.Must(template.New("sliceGenerateTest").Parse(sliceGenerateTest)) - if err := t.Execute(sb, ss.templateFields()); err != nil { +func (ss *sliceOfPtrs) generateTests(packageInfo *PackageInfo) []byte { + var sb bytes.Buffer + if err := sliceTestTemplate.Execute(&sb, ss.templateFields(packageInfo)); err != nil { panic(err) } + return sb.Bytes() } -func (ss *sliceOfPtrs) templateFields() map[string]any { +func (ss *sliceOfPtrs) templateFields(packageInfo *PackageInfo) map[string]any { return map[string]any{ "type": "sliceOfPtrs", "structName": ss.structName, @@ -347,10 +52,15 @@ func (ss *sliceOfPtrs) templateFields() map[string]any { "originElementType": "*" + ss.element.originFullName, "emptyOriginElement": "&" + ss.element.originFullName + "{}", "newElement": "new" + ss.element.structName + "((*es.orig)[i], es.state)", + "packageName": packageInfo.name, + "imports": packageInfo.imports, + "testImports": packageInfo.testImports, } } -func (ss *sliceOfPtrs) generateInternal(*bytes.Buffer) {} +func (ss *sliceOfPtrs) generateInternal(*PackageInfo) []byte { + return nil +} var _ baseStruct = (*sliceOfPtrs)(nil) @@ -369,28 +79,23 @@ func (ss *sliceOfValues) getPackageName() string { return ss.packageName } -func (ss *sliceOfValues) generateStruct(sb *bytes.Buffer) { - t := template.Must(template.New("sliceTemplate").Parse(sliceTemplate)) - if err := t.Execute(sb, ss.templateFields()); err != nil { +func (ss *sliceOfValues) generate(packageInfo *PackageInfo) []byte { + var sb bytes.Buffer + if err := sliceTemplate.Execute(&sb, ss.templateFields(packageInfo)); err != nil { panic(err) } + return sb.Bytes() } -func (ss *sliceOfValues) generateTests(sb *bytes.Buffer) { - t := template.Must(template.New("sliceTestTemplate").Parse(sliceTestTemplate)) - if err := t.Execute(sb, ss.templateFields()); err != nil { +func (ss *sliceOfValues) generateTests(packageInfo *PackageInfo) []byte { + var sb bytes.Buffer + if err := sliceTestTemplate.Execute(&sb, ss.templateFields(packageInfo)); err != nil { panic(err) } + return sb.Bytes() } -func (ss *sliceOfValues) generateTestValueHelpers(sb *bytes.Buffer) { - t := template.Must(template.New("sliceGenerateTest").Parse(sliceGenerateTest)) - if err := t.Execute(sb, ss.templateFields()); err != nil { - panic(err) - } -} - -func (ss *sliceOfValues) templateFields() map[string]any { +func (ss *sliceOfValues) templateFields(packageInfo *PackageInfo) map[string]any { return map[string]any{ "type": "sliceOfValues", "structName": ss.structName, @@ -399,9 +104,14 @@ func (ss *sliceOfValues) templateFields() map[string]any { "originElementType": ss.element.originFullName, "emptyOriginElement": ss.element.originFullName + "{}", "newElement": "new" + ss.element.structName + "(&(*es.orig)[i], es.state)", + "packageName": packageInfo.name, + "imports": packageInfo.imports, + "testImports": packageInfo.testImports, } } -func (ss *sliceOfValues) generateInternal(*bytes.Buffer) {} +func (ss *sliceOfValues) generateInternal(*PackageInfo) []byte { + return nil +} var _ baseStruct = (*sliceOfValues)(nil) diff --git a/pdata/internal/cmd/pdatagen/internal/base_structs.go b/pdata/internal/cmd/pdatagen/internal/base_structs.go index 859bb4d7c05..4cd7832f12d 100644 --- a/pdata/internal/cmd/pdatagen/internal/base_structs.go +++ b/pdata/internal/cmd/pdatagen/internal/base_structs.go @@ -5,142 +5,13 @@ package internal // import "go.opentelemetry.io/collector/pdata/internal/cmd/pda import ( "bytes" - "strings" - "text/template" ) -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. -// Important: zero-initialized instance is not valid for use. -{{- if .isCommon }} -type {{ .structName }} internal.{{ .structName }} -{{- else }} -type {{ .structName }} struct { - orig *{{ .originName }} - state *internal.State -} -{{- end }} - -func new{{ .structName }}(orig *{{ .originName }}, state *internal.State) {{ .structName }} { - {{- if .isCommon }} - return {{ .structName }}(internal.New{{ .structName }}(orig, state)) - {{- else }} - return {{ .structName }}{orig: orig, state: state} - {{- end }} -} - -// 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 }} { - state := internal.StateMutable - return new{{ .structName }}(&{{ .originName }}{}, &state) -} - -// 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 }}) { - ms.{{- if .isCommon }}getState(){{ else }}state{{ end }}.AssertMutable() - dest.{{- if .isCommon }}getState(){{ else }}state{{ end }}.AssertMutable() - *dest.{{ .origAccessor }} = *ms.{{ .origAccessor }} - *ms.{{ .origAccessor }} = {{ .originName }}{} -} - -{{ if .isCommon -}} -func (ms {{ .structName }}) getOrig() *{{ .originName }} { - return internal.GetOrig{{ .structName }}(internal.{{ .structName }}(ms)) -} - -func (ms {{ .structName }}) getState() *internal.State { - return internal.Get{{ .structName }}State(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 }}) { - dest.{{- if .isCommon }}getState(){{ else }}state{{ end }}.AssertMutable() - {{- range .fields }} - {{ .GenerateCopyToValue $.messageStruct }} - {{- end }} -}` - -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) - sharedState := internal.StateReadOnly - assert.Panics(t, func() { ms.MoveTo(new{{ .structName }}(&{{ .originName }}{}, &sharedState)) }) - assert.Panics(t, func() { new{{ .structName }}(&{{ .originName }}{}, &sharedState).MoveTo(dest) }) -} - -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) - sharedState := internal.StateReadOnly - assert.Panics(t, func() { ms.CopyTo(new{{ .structName }}(&{{ .originName }}{}, &sharedState)) }) -} - -{{ range .fields }} -{{ .GenerateAccessorsTest $.messageStruct }} -{{ end }}` - -const messageValueGenerateTestTemplate = `func {{ upperIfInternal "g" }}enerateTest{{ .structName }}() {{ .structName }} { - {{- if .isCommon }} - orig := {{ .originName }}{} - state := StateMutable - {{- end }} - tv := New{{ .structName }}({{ if .isCommon }}&orig, &state{{ 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 }} - state *State -} - -func GetOrig{{ .structName }}(ms {{ .structName }}) *{{ .originName }} { - return ms.orig -} - -func Get{{ .structName }}State(ms {{ .structName }}) *State { - return ms.state -} - -func New{{ .structName }}(orig *{{ .originName }}, state *State) {{ .structName }} { - return {{ .structName }}{orig: orig, state: state} -}` - type baseStruct interface { getName() string - generateStruct(sb *bytes.Buffer) - generateTests(sb *bytes.Buffer) - generateTestValueHelpers(sb *bytes.Buffer) - generateInternal(sb *bytes.Buffer) + generate(packageInfo *PackageInfo) []byte + generateTests(packageInfo *PackageInfo) []byte + generateInternal(packageInfo *PackageInfo) []byte } // messageValueStruct generates a struct for a proto message. The struct can be generated both as a common struct @@ -157,43 +28,31 @@ func (ms *messageValueStruct) getName() string { return ms.structName } -func (ms *messageValueStruct) generateStruct(sb *bytes.Buffer) { - t := template.Must(template.New("messageValueTemplate").Parse(messageValueTemplate)) - if err := t.Execute(sb, ms.templateFields()); err != nil { +func (ms *messageValueStruct) generate(packageInfo *PackageInfo) []byte { + var sb bytes.Buffer + if err := messageTemplate.Execute(&sb, ms.templateFields(packageInfo)); err != nil { panic(err) } + return sb.Bytes() } -func (ms *messageValueStruct) generateTests(sb *bytes.Buffer) { - 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) { - funcs := template.FuncMap{ - "upperIfInternal": func(in string) string { - if usedByOtherDataTypes(ms.packageName) { - return strings.ToUpper(in) - } - return in - }, - } - t := template.Must(template.New("messageValueGenerateTestTemplate").Funcs(funcs).Parse(messageValueGenerateTestTemplate)) - if err := t.Execute(sb, ms.templateFields()); err != nil { +func (ms *messageValueStruct) generateTests(packageInfo *PackageInfo) []byte { + var sb bytes.Buffer + if err := messageTestTemplate.Execute(&sb, ms.templateFields(packageInfo)); err != nil { panic(err) } + return sb.Bytes() } -func (ms *messageValueStruct) generateInternal(sb *bytes.Buffer) { - t := template.Must(template.New("messageValueAliasTemplate").Parse(messageValueAliasTemplate)) - if err := t.Execute(sb, ms.templateFields()); err != nil { +func (ms *messageValueStruct) generateInternal(packageInfo *PackageInfo) []byte { + var sb bytes.Buffer + if err := messageInternalTemplate.Execute(&sb, ms.templateFields(packageInfo)); err != nil { panic(err) } + return sb.Bytes() } -func (ms *messageValueStruct) templateFields() map[string]any { +func (ms *messageValueStruct) templateFields(packageInfo *PackageInfo) map[string]any { return map[string]any{ "messageStruct": ms, "fields": ms.fields, @@ -208,6 +67,9 @@ func (ms *messageValueStruct) templateFields() map[string]any { "description": ms.description, "isCommon": usedByOtherDataTypes(ms.packageName), "origAccessor": origAccessor(ms), + "packageName": packageInfo.name, + "imports": packageInfo.imports, + "testImports": packageInfo.testImports, } } diff --git a/pdata/internal/cmd/pdatagen/internal/packages.go b/pdata/internal/cmd/pdatagen/internal/packages.go index 13d98d6703c..47708bc975e 100644 --- a/pdata/internal/cmd/pdatagen/internal/packages.go +++ b/pdata/internal/cmd/pdatagen/internal/packages.go @@ -4,7 +4,6 @@ package internal // import "go.opentelemetry.io/collector/pdata/internal/cmd/pdatagen/internal" import ( - "bytes" "os" "path/filepath" "strings" @@ -31,40 +30,23 @@ var AllPackages = []*Package{ // Package is a struct used to generate files. type Package struct { + info *PackageInfo + // Can be any of sliceOfPtrs, sliceOfValues, messageValueStruct. + structs []baseStruct +} + +type PackageInfo struct { name string path string imports []string testImports []string - // Can be any of sliceOfPtrs, sliceOfValues, messageValueStruct, or messagePtrStruct - 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 { - var sb bytes.Buffer - generateHeader(&sb, p.name) - - // Add imports - sb.WriteString("import (" + newLine) - for _, imp := range p.imports { - if imp != "" { - sb.WriteString("\t" + imp + newLine) - } else { - sb.WriteString(newLine) - } - } - sb.WriteString(")") - - // Write all structs - sb.WriteString(newLine + newLine) - s.generateStruct(&sb) - sb.WriteString(newLine) - - path := filepath.Join("pdata", p.path, "generated_"+strings.ToLower(s.getName())+".go") - if err := os.WriteFile(path, sb.Bytes(), 0600); err != nil { + path := filepath.Join("pdata", p.info.path, "generated_"+strings.ToLower(s.getName())+".go") + if err := os.WriteFile(path, s.generate(p.info), 0600); err != nil { return err } } @@ -74,30 +56,8 @@ func (p *Package) GenerateFiles() error { // GenerateTestFiles generates files with tests for the configured data structures for this Package. func (p *Package) GenerateTestFiles() error { for _, s := range p.structs { - var sb bytes.Buffer - generateHeader(&sb, p.name) - - // Add imports - sb.WriteString("import (" + newLine) - for _, imp := range p.testImports { - if imp != "" { - sb.WriteString("\t" + imp + newLine) - } else { - sb.WriteString(newLine) - } - } - sb.WriteString(")") - - // Write all tests - sb.WriteString(newLine + newLine) - s.generateTests(&sb) - if !usedByOtherDataTypes(p.name) { - sb.WriteString(newLine + newLine) - s.generateTestValueHelpers(&sb) - } - - path := filepath.Join("pdata", p.path, "generated_"+strings.ToLower(s.getName())+"_test.go") - if err := os.WriteFile(path, sb.Bytes(), 0600); err != nil { + path := filepath.Join("pdata", p.info.path, "generated_"+strings.ToLower(s.getName())+"_test.go") + if err := os.WriteFile(path, s.generateTests(p.info), 0600); err != nil { return err } } @@ -106,52 +66,19 @@ func (p *Package) GenerateTestFiles() error { // GenerateInternalFiles generates files with internal pdata structures for this Package. func (p *Package) GenerateInternalFiles() error { - if !usedByOtherDataTypes(p.name) { + if !usedByOtherDataTypes(p.info.name) { return nil } for _, s := range p.structs { - var sb bytes.Buffer - generateHeader(&sb, "internal") - - // Add imports - sb.WriteString("import (" + newLine) - for _, imp := range p.imports { - if imp == `"go.opentelemetry.io/collector/pdata/internal"` { - continue - } - if imp != "" { - sb.WriteString("\t" + imp + newLine) - } else { - sb.WriteString(newLine) - } - } - sb.WriteString(")") - - // Write all types and funcs - s.generateInternal(&sb) - sb.WriteString(newLine) - - // Write all tests generate value - sb.WriteString(newLine + newLine) - s.generateTestValueHelpers(&sb) - sb.WriteString(newLine) - path := filepath.Join("pdata", "internal", "generated_wrapper_"+strings.ToLower(s.getName())+".go") - if err := os.WriteFile(path, sb.Bytes(), 0600); err != nil { + if err := os.WriteFile(path, s.generateInternal(p.info), 0600); err != nil { return err } } return nil } -func generateHeader(sb *bytes.Buffer, packageName string) { - sb.WriteString(header) - sb.WriteString(newLine + newLine) - sb.WriteString("package " + packageName) - sb.WriteString(newLine + newLine) -} - // usedByOtherDataTypes defines if the package is used by other data types and orig fields of the package's structs // need to be accessible from other pdata packages. func usedByOtherDataTypes(packageName string) bool { diff --git a/pdata/internal/cmd/pdatagen/internal/pcommon_package.go b/pdata/internal/cmd/pdatagen/internal/pcommon_package.go index 6491792b4cf..d6085334f56 100644 --- a/pdata/internal/cmd/pdatagen/internal/pcommon_package.go +++ b/pdata/internal/cmd/pdatagen/internal/pcommon_package.go @@ -4,19 +4,21 @@ package internal // import "go.opentelemetry.io/collector/pdata/internal/cmd/pdatagen/internal" var pcommon = &Package{ - name: "pcommon", - path: "pcommon", - imports: []string{ - `"go.opentelemetry.io/collector/pdata/internal"`, - `otlpcommon "go.opentelemetry.io/collector/pdata/internal/data/protogen/common/v1"`, - `otlpresource "go.opentelemetry.io/collector/pdata/internal/data/protogen/resource/v1"`, - }, - testImports: []string{ - `"testing"`, - ``, - `"github.com/stretchr/testify/assert"`, - ``, - `"go.opentelemetry.io/collector/pdata/internal"`, + info: &PackageInfo{ + name: "pcommon", + path: "pcommon", + imports: []string{ + `"go.opentelemetry.io/collector/pdata/internal"`, + `otlpcommon "go.opentelemetry.io/collector/pdata/internal/data/protogen/common/v1"`, + `otlpresource "go.opentelemetry.io/collector/pdata/internal/data/protogen/resource/v1"`, + }, + testImports: []string{ + `"testing"`, + ``, + `"github.com/stretchr/testify/assert"`, + ``, + `"go.opentelemetry.io/collector/pdata/internal"`, + }, }, structs: []baseStruct{ scope, diff --git a/pdata/internal/cmd/pdatagen/internal/plog_package.go b/pdata/internal/cmd/pdatagen/internal/plog_package.go index d452ea4324e..5e65b6e5fae 100644 --- a/pdata/internal/cmd/pdatagen/internal/plog_package.go +++ b/pdata/internal/cmd/pdatagen/internal/plog_package.go @@ -4,26 +4,28 @@ package internal // import "go.opentelemetry.io/collector/pdata/internal/cmd/pdatagen/internal" var plog = &Package{ - name: "plog", - path: "plog", - imports: []string{ - `"sort"`, - ``, - `"go.opentelemetry.io/collector/pdata/internal"`, - `"go.opentelemetry.io/collector/pdata/internal/data"`, - `otlplogs "go.opentelemetry.io/collector/pdata/internal/data/protogen/logs/v1"`, - `"go.opentelemetry.io/collector/pdata/pcommon"`, - }, - testImports: []string{ - `"testing"`, - `"unsafe"`, - ``, - `"github.com/stretchr/testify/assert"`, - ``, - `"go.opentelemetry.io/collector/pdata/internal"`, - `"go.opentelemetry.io/collector/pdata/internal/data"`, - `otlplogs "go.opentelemetry.io/collector/pdata/internal/data/protogen/logs/v1"`, - `"go.opentelemetry.io/collector/pdata/pcommon"`, + info: &PackageInfo{ + name: "plog", + path: "plog", + imports: []string{ + `"sort"`, + ``, + `"go.opentelemetry.io/collector/pdata/internal"`, + `"go.opentelemetry.io/collector/pdata/internal/data"`, + `otlplogs "go.opentelemetry.io/collector/pdata/internal/data/protogen/logs/v1"`, + `"go.opentelemetry.io/collector/pdata/pcommon"`, + }, + testImports: []string{ + `"testing"`, + `"unsafe"`, + ``, + `"github.com/stretchr/testify/assert"`, + ``, + `"go.opentelemetry.io/collector/pdata/internal"`, + `"go.opentelemetry.io/collector/pdata/internal/data"`, + `otlplogs "go.opentelemetry.io/collector/pdata/internal/data/protogen/logs/v1"`, + `"go.opentelemetry.io/collector/pdata/pcommon"`, + }, }, structs: []baseStruct{ resourceLogsSlice, diff --git a/pdata/internal/cmd/pdatagen/internal/plogotlp_package.go b/pdata/internal/cmd/pdatagen/internal/plogotlp_package.go index 4a91a4c96da..a5d33fb5da5 100644 --- a/pdata/internal/cmd/pdatagen/internal/plogotlp_package.go +++ b/pdata/internal/cmd/pdatagen/internal/plogotlp_package.go @@ -7,15 +7,19 @@ import ( ) var plogotlp = &Package{ - name: "plogotlp", - path: filepath.Join("plog", "plogotlp"), - imports: []string{ - `otlpcollectorlog "go.opentelemetry.io/collector/pdata/internal/data/protogen/collector/logs/v1"`, - }, - testImports: []string{ - `"testing"`, - ``, - `"github.com/stretchr/testify/assert"`, + info: &PackageInfo{ + name: "plogotlp", + path: filepath.Join("plog", "plogotlp"), + imports: []string{ + `otlpcollectorlog "go.opentelemetry.io/collector/pdata/internal/data/protogen/collector/logs/v1"`, + }, + testImports: []string{ + `"testing"`, + ``, + `"github.com/stretchr/testify/assert"`, + ``, + `"go.opentelemetry.io/collector/pdata/internal"`, + }, }, structs: []baseStruct{ exportLogsPartialSuccess, diff --git a/pdata/internal/cmd/pdatagen/internal/pmetric_package.go b/pdata/internal/cmd/pdatagen/internal/pmetric_package.go index 68aee5219f9..e6e8e3a1901 100644 --- a/pdata/internal/cmd/pdatagen/internal/pmetric_package.go +++ b/pdata/internal/cmd/pdatagen/internal/pmetric_package.go @@ -4,26 +4,28 @@ package internal // import "go.opentelemetry.io/collector/pdata/internal/cmd/pdatagen/internal" var pmetric = &Package{ - name: "pmetric", - path: "pmetric", - imports: []string{ - `"sort"`, - ``, - `"go.opentelemetry.io/collector/pdata/internal"`, - `"go.opentelemetry.io/collector/pdata/internal/data"`, - `otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1"`, - `"go.opentelemetry.io/collector/pdata/pcommon"`, - }, - testImports: []string{ - `"testing"`, - `"unsafe"`, - ``, - `"github.com/stretchr/testify/assert"`, - ``, - `"go.opentelemetry.io/collector/pdata/internal"`, - `"go.opentelemetry.io/collector/pdata/internal/data"`, - `otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1"`, - `"go.opentelemetry.io/collector/pdata/pcommon"`, + info: &PackageInfo{ + name: "pmetric", + path: "pmetric", + imports: []string{ + `"sort"`, + ``, + `"go.opentelemetry.io/collector/pdata/internal"`, + `"go.opentelemetry.io/collector/pdata/internal/data"`, + `otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1"`, + `"go.opentelemetry.io/collector/pdata/pcommon"`, + }, + testImports: []string{ + `"testing"`, + `"unsafe"`, + ``, + `"github.com/stretchr/testify/assert"`, + ``, + `"go.opentelemetry.io/collector/pdata/internal"`, + `"go.opentelemetry.io/collector/pdata/internal/data"`, + `otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1"`, + `"go.opentelemetry.io/collector/pdata/pcommon"`, + }, }, structs: []baseStruct{ resourceMetricsSlice, diff --git a/pdata/internal/cmd/pdatagen/internal/pmetricotlp_package.go b/pdata/internal/cmd/pdatagen/internal/pmetricotlp_package.go index 33a96aed184..591e9a7ec0d 100644 --- a/pdata/internal/cmd/pdatagen/internal/pmetricotlp_package.go +++ b/pdata/internal/cmd/pdatagen/internal/pmetricotlp_package.go @@ -8,15 +8,19 @@ import ( ) var pmetricotlp = &Package{ - name: "pmetricotlp", - path: filepath.Join("pmetric", "pmetricotlp"), - imports: []string{ - `otlpcollectormetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/collector/metrics/v1"`, - }, - testImports: []string{ - `"testing"`, - ``, - `"github.com/stretchr/testify/assert"`, + info: &PackageInfo{ + name: "pmetricotlp", + path: filepath.Join("pmetric", "pmetricotlp"), + imports: []string{ + `otlpcollectormetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/collector/metrics/v1"`, + }, + testImports: []string{ + `"testing"`, + ``, + `"github.com/stretchr/testify/assert"`, + ``, + `"go.opentelemetry.io/collector/pdata/internal"`, + }, }, structs: []baseStruct{ exportMetricsPartialSuccess, diff --git a/pdata/internal/cmd/pdatagen/internal/pprofile_package.go b/pdata/internal/cmd/pdatagen/internal/pprofile_package.go index 2e740137749..7071021b27d 100644 --- a/pdata/internal/cmd/pdatagen/internal/pprofile_package.go +++ b/pdata/internal/cmd/pdatagen/internal/pprofile_package.go @@ -4,23 +4,25 @@ package internal // import "go.opentelemetry.io/collector/pdata/internal/cmd/pdatagen/internal" var pprofile = &Package{ - name: "pprofile", - path: "pprofile", - imports: []string{ - `"go.opentelemetry.io/collector/pdata/internal"`, - `"go.opentelemetry.io/collector/pdata/internal/data"`, - `otlpprofiles "go.opentelemetry.io/collector/pdata/internal/data/protogen/profiles/v1experimental"`, - `"go.opentelemetry.io/collector/pdata/pcommon"`, - }, - testImports: []string{ - `"testing"`, - `"unsafe"`, - ``, - `"github.com/stretchr/testify/assert"`, - ``, - `"go.opentelemetry.io/collector/pdata/internal"`, - `otlpprofiles "go.opentelemetry.io/collector/pdata/internal/data/protogen/profiles/v1experimental"`, - `"go.opentelemetry.io/collector/pdata/pcommon"`, + info: &PackageInfo{ + name: "pprofile", + path: "pprofile", + imports: []string{ + `"go.opentelemetry.io/collector/pdata/internal"`, + `"go.opentelemetry.io/collector/pdata/internal/data"`, + `otlpprofiles "go.opentelemetry.io/collector/pdata/internal/data/protogen/profiles/v1experimental"`, + `"go.opentelemetry.io/collector/pdata/pcommon"`, + }, + testImports: []string{ + `"testing"`, + `"unsafe"`, + ``, + `"github.com/stretchr/testify/assert"`, + ``, + `"go.opentelemetry.io/collector/pdata/internal"`, + `otlpprofiles "go.opentelemetry.io/collector/pdata/internal/data/protogen/profiles/v1experimental"`, + `"go.opentelemetry.io/collector/pdata/pcommon"`, + }, }, structs: []baseStruct{ resourceProfilesSlice, diff --git a/pdata/internal/cmd/pdatagen/internal/pprofile_otlp_package.go b/pdata/internal/cmd/pdatagen/internal/pprofileotlp_package.go similarity index 68% rename from pdata/internal/cmd/pdatagen/internal/pprofile_otlp_package.go rename to pdata/internal/cmd/pdatagen/internal/pprofileotlp_package.go index ddd3a5df437..9a94f3945a0 100644 --- a/pdata/internal/cmd/pdatagen/internal/pprofile_otlp_package.go +++ b/pdata/internal/cmd/pdatagen/internal/pprofileotlp_package.go @@ -7,15 +7,19 @@ import ( ) var pprofileotlp = &Package{ - name: "pprofileotlp", - path: filepath.Join("pprofile", "pprofileotlp"), - imports: []string{ - `otlpcollectorprofile "go.opentelemetry.io/collector/pdata/internal/data/protogen/collector/profiles/v1experimental"`, - }, - testImports: []string{ - `"testing"`, - ``, - `"github.com/stretchr/testify/assert"`, + info: &PackageInfo{ + name: "pprofileotlp", + path: filepath.Join("pprofile", "pprofileotlp"), + imports: []string{ + `otlpcollectorprofile "go.opentelemetry.io/collector/pdata/internal/data/protogen/collector/profiles/v1experimental"`, + }, + testImports: []string{ + `"testing"`, + ``, + `"github.com/stretchr/testify/assert"`, + ``, + `"go.opentelemetry.io/collector/pdata/internal"`, + }, }, structs: []baseStruct{ exportProfilesPartialSuccess, diff --git a/pdata/internal/cmd/pdatagen/internal/primitive_slice_structs.go b/pdata/internal/cmd/pdatagen/internal/primitive_slice_structs.go index 11ddf6d7c12..0e3c45d6b91 100644 --- a/pdata/internal/cmd/pdatagen/internal/primitive_slice_structs.go +++ b/pdata/internal/cmd/pdatagen/internal/primitive_slice_structs.go @@ -6,234 +6,8 @@ package internal // import "go.opentelemetry.io/collector/pdata/internal/cmd/pda import ( "bytes" "strings" - "text/template" ) -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. -// Important: zero-initialized instance is not valid for use. -type {{ .structName }} internal.{{ .structName }} - -func (ms {{ .structName }}) getOrig() *[]{{ .itemType }} { - return internal.GetOrig{{ .structName }}(internal.{{ .structName }}(ms)) -} - -func (ms {{ .structName }}) getState() *internal.State { - return internal.Get{{ .structName }}State(internal.{{ .structName }}(ms)) -} - -// New{{ .structName }} creates a new empty {{ .structName }}. -func New{{ .structName }}() {{ .structName }} { - orig := []{{ .itemType }}(nil) - state := internal.StateMutable - return {{ .structName }}(internal.New{{ .structName }}(&orig, &state)) -} - -// 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.getState().AssertMutable() - *ms.getOrig() = copy{{ .structName }}(*ms.getOrig(), val) -} - -// 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 }} { - return (*ms.getOrig())[i] -} - -// SetAt sets {{ .itemType }} item at particular index. -// Equivalent of {{ .lowerStructName }}[i] = val -func (ms {{ .structName }}) SetAt(i int, val {{ .itemType }}) { - ms.getState().AssertMutable() - (*ms.getOrig())[i] = val -} - -// 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) { - ms.getState().AssertMutable() - oldCap := cap(*ms.getOrig()) - if newCap <= oldCap { - return - } - - 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 }}) { - ms.getState().AssertMutable() - *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 }}) { - ms.getState().AssertMutable() - dest.getState().AssertMutable() - *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.getState().AssertMutable() - *dest.getOrig() = copy{{ .structName }}(*dest.getOrig(), *ms.getOrig()) -} - -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 }}() - assert.Equal(t, 0, ms.Len()) - ms.FromRaw([]{{ .itemType }}{ {{ .testOrigVal }} }) - assert.Equal(t, 3, ms.Len()) - assert.Equal(t, []{{ .itemType }}{ {{ .testOrigVal }} }, ms.AsRaw()) - ms.SetAt(1, {{ .itemType }}( {{ .testSetVal }} )) - assert.Equal(t, []{{ .itemType }}{ {{ .testNewVal }} }, ms.AsRaw()) - ms.FromRaw([]{{ .itemType }}{ {{ index .testInterfaceOrigVal 2 }} }) - assert.Equal(t, 1, ms.Len()) - {{- if eq .itemType "float64" }} - assert.InDelta(t, {{ .itemType }}({{ index .testInterfaceOrigVal 2 }}), ms.At(0), 0.01) - {{- else }} - assert.Equal(t, {{ .itemType }}({{ index .testInterfaceOrigVal 2 }}), ms.At(0)) - {{- end }} - - cp := New{{ .structName }}() - ms.CopyTo(cp) - ms.SetAt(0, {{ .itemType }}( {{ index .testInterfaceOrigVal 1 }} )) - {{- if eq .itemType "float64" }} - assert.InDelta(t, {{ .itemType }}({{ index .testInterfaceOrigVal 1 }}), ms.At(0), 0.01) - {{- else }} - assert.Equal(t, {{ .itemType }}({{ index .testInterfaceOrigVal 1 }}), ms.At(0)) - {{- end }} - {{- if eq .itemType "float64" }} - assert.InDelta(t, {{ .itemType }}({{ index .testInterfaceOrigVal 2 }}), cp.At(0), 0.01) - {{- else }} - assert.Equal(t, {{ .itemType }}({{ index .testInterfaceOrigVal 2 }}), cp.At(0)) - {{- end }} - ms.CopyTo(cp) - {{- if eq .itemType "float64" }} - assert.InDelta(t, {{ .itemType }}({{ index .testInterfaceOrigVal 1 }}), cp.At(0), 0.01) - {{- else }} - assert.Equal(t, {{ .itemType }}({{ index .testInterfaceOrigVal 1 }}), cp.At(0)) - {{- end }} - - mv := New{{ .structName }}() - ms.MoveTo(mv) - assert.Equal(t, 0, ms.Len()) - assert.Equal(t, 1, mv.Len()) - {{- if eq .itemType "float64" }} - assert.InDelta(t, {{ .itemType }}({{index .testInterfaceOrigVal 1 }}), mv.At(0), 0.01) - {{- else }} - assert.Equal(t, {{ .itemType }}({{index .testInterfaceOrigVal 1 }}), mv.At(0)) - {{- end }} - ms.FromRaw([]{{ .itemType }}{ {{ .testOrigVal }} }) - ms.MoveTo(mv) - assert.Equal(t, 3, mv.Len()) - {{- if eq .itemType "float64" }} - assert.InDelta(t, {{ .itemType }}({{index .testInterfaceOrigVal 0 }}), mv.At(0), 0.01) - {{- else }} - assert.Equal(t, {{ .itemType }}({{index .testInterfaceOrigVal 0 }}), mv.At(0)) - {{- end }} -} - -func Test{{ .structName }}ReadOnly(t *testing.T) { - raw := []{{ .itemType }}{ {{ .testOrigVal }}} - state := internal.StateReadOnly - ms := {{ .structName }}(internal.New{{ .structName }}(&raw, &state)) - - assert.Equal(t, 3, ms.Len()) - {{- if eq .itemType "float64" }} - assert.InDelta(t, {{ .itemType }}( {{index .testInterfaceOrigVal 0 }} ), ms.At(0), 0.01) - {{- else }} - assert.Equal(t, {{ .itemType }}({{ index .testInterfaceOrigVal 0 }}), ms.At(0)) - {{- end }} - assert.Panics(t, func() { ms.Append({{ index .testInterfaceOrigVal 0 }}) }) - assert.Panics(t, func() { ms.EnsureCapacity(2) }) - assert.Equal(t, raw, ms.AsRaw()) - assert.Panics(t, func() { ms.FromRaw(raw) }) - - ms2 := New{{ .structName }}() - ms.CopyTo(ms2) - assert.Equal(t, ms.AsRaw(), ms2.AsRaw()) - assert.Panics(t, func() { ms2.CopyTo(ms) }) - - assert.Panics(t, func() { ms.MoveTo(ms2) }) - assert.Panics(t, func() { ms2.MoveTo(ms) }) -} - -func Test{{ .structName }}Append(t *testing.T) { - ms := New{{ .structName }}() - ms.FromRaw([]{{ .itemType }}{ {{ .testOrigVal }} }) - ms.Append({{ .testSetVal }}, {{ .testSetVal }}) - assert.Equal(t, 5, ms.Len()) - {{- if eq .itemType "float64" }} - assert.InDelta(t, {{ .itemType }}({{ .testSetVal }} ), ms.At(4), 0.01) - {{- else }} - assert.Equal(t, {{ .itemType }}({{ .testSetVal }}), ms.At(4)) - {{- end }} -} - -func Test{{ .structName }}EnsureCapacity(t *testing.T) { - ms := New{{ .structName }}() - ms.EnsureCapacity(4) - assert.Equal(t, 4, cap(*ms.getOrig())) - ms.EnsureCapacity(2) - assert.Equal(t, 4, cap(*ms.getOrig())) -}` - -const primitiveSliceInternalTemplate = ` -type {{ .structName }} struct { - orig *[]{{ .itemType }} - state *State -} - -func GetOrig{{ .structName }}(ms {{ .structName }}) *[]{{ .itemType }} { - return ms.orig -} - -func Get{{ .structName }}State(ms {{ .structName }}) *State { - return ms.state -} - -func New{{ .structName }}(orig *[]{{ .itemType }}, state *State) {{ .structName }} { - return {{ .structName }}{orig: orig, state: state} -} - -func FillTest{{ .structName }}(tv {{ .structName}}) { -} - -func GenerateTest{{ .structName }}() {{ .structName }} { - state := StateMutable - var orig []{{ .itemType }} = nil - - return {{ .structName }}{&orig, &state} -}` - // primitiveSliceStruct generates a struct for a slice of primitive value elements. The structs are always generated // in a way that they can be used as fields in structs from other packages (using the internal package). type primitiveSliceStruct struct { @@ -255,30 +29,31 @@ func (iss *primitiveSliceStruct) getPackageName() string { return iss.packageName } -func (iss *primitiveSliceStruct) generateStruct(sb *bytes.Buffer) { - t := template.Must(template.New("primitiveSliceTemplate").Parse(primitiveSliceTemplate)) - if err := t.Execute(sb, iss.templateFields()); err != nil { +func (iss *primitiveSliceStruct) generate(packageInfo *PackageInfo) []byte { + var sb bytes.Buffer + if err := primitiveSliceTemplate.Execute(&sb, iss.templateFields(packageInfo)); err != nil { panic(err) } + return sb.Bytes() } -func (iss *primitiveSliceStruct) generateTests(sb *bytes.Buffer) { - t := template.Must(template.New("immutableSliceTestTemplate").Parse(immutableSliceTestTemplate)) - if err := t.Execute(sb, iss.templateFields()); err != nil { +func (iss *primitiveSliceStruct) generateTests(packageInfo *PackageInfo) []byte { + var sb bytes.Buffer + if err := primitiveSliceTestTemplate.Execute(&sb, iss.templateFields(packageInfo)); err != nil { panic(err) } + return sb.Bytes() } -func (iss *primitiveSliceStruct) generateTestValueHelpers(*bytes.Buffer) {} - -func (iss *primitiveSliceStruct) generateInternal(sb *bytes.Buffer) { - t := template.Must(template.New("primitiveSliceInternalTemplate").Parse(primitiveSliceInternalTemplate)) - if err := t.Execute(sb, iss.templateFields()); err != nil { +func (iss *primitiveSliceStruct) generateInternal(packageInfo *PackageInfo) []byte { + var sb bytes.Buffer + if err := primitiveSliceInternalTemplate.Execute(&sb, iss.templateFields(packageInfo)); err != nil { panic(err) } + return sb.Bytes() } -func (iss *primitiveSliceStruct) templateFields() map[string]any { +func (iss *primitiveSliceStruct) templateFields(packageInfo *PackageInfo) map[string]any { return map[string]any{ "structName": iss.structName, "itemType": iss.itemType, @@ -287,5 +62,8 @@ func (iss *primitiveSliceStruct) templateFields() map[string]any { "testInterfaceOrigVal": iss.testInterfaceOrigVal, "testSetVal": iss.testSetVal, "testNewVal": iss.testNewVal, + "packageName": packageInfo.name, + "imports": packageInfo.imports, + "testImports": packageInfo.testImports, } } diff --git a/pdata/internal/cmd/pdatagen/internal/ptrace_package.go b/pdata/internal/cmd/pdatagen/internal/ptrace_package.go index bb4345294d9..d04192b7455 100644 --- a/pdata/internal/cmd/pdatagen/internal/ptrace_package.go +++ b/pdata/internal/cmd/pdatagen/internal/ptrace_package.go @@ -4,26 +4,28 @@ package internal // import "go.opentelemetry.io/collector/pdata/internal/cmd/pdatagen/internal" var ptrace = &Package{ - name: "ptrace", - path: "ptrace", - imports: []string{ - `"sort"`, - ``, - `"go.opentelemetry.io/collector/pdata/internal"`, - `"go.opentelemetry.io/collector/pdata/internal/data"`, - `otlptrace "go.opentelemetry.io/collector/pdata/internal/data/protogen/trace/v1"`, - `"go.opentelemetry.io/collector/pdata/pcommon"`, - }, - testImports: []string{ - `"testing"`, - `"unsafe"`, - ``, - `"github.com/stretchr/testify/assert"`, - ``, - `"go.opentelemetry.io/collector/pdata/internal"`, - `"go.opentelemetry.io/collector/pdata/internal/data"`, - `otlptrace "go.opentelemetry.io/collector/pdata/internal/data/protogen/trace/v1"`, - `"go.opentelemetry.io/collector/pdata/pcommon"`, + info: &PackageInfo{ + name: "ptrace", + path: "ptrace", + imports: []string{ + `"sort"`, + ``, + `"go.opentelemetry.io/collector/pdata/internal"`, + `"go.opentelemetry.io/collector/pdata/internal/data"`, + `otlptrace "go.opentelemetry.io/collector/pdata/internal/data/protogen/trace/v1"`, + `"go.opentelemetry.io/collector/pdata/pcommon"`, + }, + testImports: []string{ + `"testing"`, + `"unsafe"`, + ``, + `"github.com/stretchr/testify/assert"`, + ``, + `"go.opentelemetry.io/collector/pdata/internal"`, + `"go.opentelemetry.io/collector/pdata/internal/data"`, + `otlptrace "go.opentelemetry.io/collector/pdata/internal/data/protogen/trace/v1"`, + `"go.opentelemetry.io/collector/pdata/pcommon"`, + }, }, structs: []baseStruct{ resourceSpansSlice, diff --git a/pdata/internal/cmd/pdatagen/internal/ptraceotlp_package.go b/pdata/internal/cmd/pdatagen/internal/ptraceotlp_package.go index 621f42bf2a7..ca574f1b4d7 100644 --- a/pdata/internal/cmd/pdatagen/internal/ptraceotlp_package.go +++ b/pdata/internal/cmd/pdatagen/internal/ptraceotlp_package.go @@ -8,15 +8,19 @@ import ( ) var ptraceotlp = &Package{ - name: "ptraceotlp", - path: filepath.Join("ptrace", "ptraceotlp"), - imports: []string{ - `otlpcollectortrace "go.opentelemetry.io/collector/pdata/internal/data/protogen/collector/trace/v1"`, - }, - testImports: []string{ - `"testing"`, - ``, - `"github.com/stretchr/testify/assert"`, + info: &PackageInfo{ + name: "ptraceotlp", + path: filepath.Join("ptrace", "ptraceotlp"), + imports: []string{ + `otlpcollectortrace "go.opentelemetry.io/collector/pdata/internal/data/protogen/collector/trace/v1"`, + }, + testImports: []string{ + `"testing"`, + ``, + `"github.com/stretchr/testify/assert"`, + ``, + `"go.opentelemetry.io/collector/pdata/internal"`, + }, }, structs: []baseStruct{ exportTracePartialSuccess, diff --git a/pdata/internal/cmd/pdatagen/internal/templates.go b/pdata/internal/cmd/pdatagen/internal/templates.go new file mode 100644 index 00000000000..e7218752979 --- /dev/null +++ b/pdata/internal/cmd/pdatagen/internal/templates.go @@ -0,0 +1,47 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package internal // import "go.opentelemetry.io/collector/pdata/internal/cmd/pdatagen/internal" + +import ( + _ "embed" + "text/template" +) + +var ( + //go:embed templates/message.go.tmpl + messageTemplateBytes []byte + messageTemplate = parseTemplate("message.go", messageTemplateBytes) + + //go:embed templates/message_internal.go.tmpl + messageInternalTemplateBytes []byte + messageInternalTemplate = parseTemplate("message_internal.go", messageInternalTemplateBytes) + + //go:embed templates/message_test.go.tmpl + messageTestTemplateBytes []byte + messageTestTemplate = parseTemplate("message_test.go", messageTestTemplateBytes) + + //go:embed templates/primitive_slice.go.tmpl + primitiveSliceTemplateBytes []byte + primitiveSliceTemplate = parseTemplate("primitive_slice.go", primitiveSliceTemplateBytes) + + //go:embed templates/primitive_slice_internal.go.tmpl + primitiveSliceInternalTemplateBytes []byte + primitiveSliceInternalTemplate = parseTemplate("primitive_slice_internal.go", primitiveSliceInternalTemplateBytes) + + //go:embed templates/primitive_slice_test.go.tmpl + primitiveSliceTestTemplateBytes []byte + primitiveSliceTestTemplate = parseTemplate("primitive_slice_test.go", primitiveSliceTestTemplateBytes) + + //go:embed templates/slice.go.tmpl + sliceTemplateBytes []byte + sliceTemplate = parseTemplate("slice.go", sliceTemplateBytes) + + //go:embed templates/slice_test.go.tmpl + sliceTestTemplateBytes []byte + sliceTestTemplate = parseTemplate("slice_test.go", sliceTestTemplateBytes) +) + +func parseTemplate(name string, bytes []byte) *template.Template { + return template.Must(template.New(name).Parse(string(bytes))) +} diff --git a/pdata/internal/cmd/pdatagen/internal/templates/message.go.tmpl b/pdata/internal/cmd/pdatagen/internal/templates/message.go.tmpl new file mode 100644 index 00000000000..d7e93b9f31d --- /dev/null +++ b/pdata/internal/cmd/pdatagen/internal/templates/message.go.tmpl @@ -0,0 +1,77 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by "pdata/internal/cmd/pdatagen/main.go". DO NOT EDIT. +// To regenerate this file run "make genpdata". + +package {{ .packageName }} + +import ( +{{ range $index, $element := .imports -}} +{{ $element }} +{{ end }} +) + +{{ .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. +// Important: zero-initialized instance is not valid for use. +{{- if .isCommon }} +type {{ .structName }} internal.{{ .structName }} +{{- else }} +type {{ .structName }} struct { + orig *{{ .originName }} + state *internal.State +} +{{- end }} + +func new{{ .structName }}(orig *{{ .originName }}, state *internal.State) {{ .structName }} { + {{- if .isCommon }} + return {{ .structName }}(internal.New{{ .structName }}(orig, state)) + {{- else }} + return {{ .structName }}{orig: orig, state: state} + {{- end }} +} + +// 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 }} { + state := internal.StateMutable + return new{{ .structName }}(&{{ .originName }}{}, &state) +} + +// 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 }}) { + ms.{{- if .isCommon }}getState(){{ else }}state{{ end }}.AssertMutable() + dest.{{- if .isCommon }}getState(){{ else }}state{{ end }}.AssertMutable() + *dest.{{ .origAccessor }} = *ms.{{ .origAccessor }} + *ms.{{ .origAccessor }} = {{ .originName }}{} +} + +{{ if .isCommon -}} +func (ms {{ .structName }}) getOrig() *{{ .originName }} { + return internal.GetOrig{{ .structName }}(internal.{{ .structName }}(ms)) +} + +func (ms {{ .structName }}) getState() *internal.State { + return internal.Get{{ .structName }}State(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 }}) { + dest.{{- if .isCommon }}getState(){{ else }}state{{ end }}.AssertMutable() + {{- range .fields }} + {{ .GenerateCopyToValue $.messageStruct }} + {{- end }} +} diff --git a/pdata/internal/cmd/pdatagen/internal/templates/message_internal.go.tmpl b/pdata/internal/cmd/pdatagen/internal/templates/message_internal.go.tmpl new file mode 100644 index 00000000000..6f1c0b41979 --- /dev/null +++ b/pdata/internal/cmd/pdatagen/internal/templates/message_internal.go.tmpl @@ -0,0 +1,46 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by "pdata/internal/cmd/pdatagen/main.go". DO NOT EDIT. +// To regenerate this file run "make genpdata". + +package internal + +import ( +{{ range $index, $element := .imports -}} +{{ if ne $element "go.opentelemetry.io/collector/pdata/internal" }} +{{ $element }} +{{ end }} +{{ end }} +) + +type {{ .structName }} struct { + orig *{{ .originName }} + state *State +} + +func GetOrig{{ .structName }}(ms {{ .structName }}) *{{ .originName }} { + return ms.orig +} + +func Get{{ .structName }}State(ms {{ .structName }}) *State { + return ms.state +} + +func New{{ .structName }}(orig *{{ .originName }}, state *State) {{ .structName }} { + return {{ .structName }}{orig: orig, state: state} +} + +func GenerateTest{{ .structName }}() {{ .structName }} { + orig := {{ .originName }}{} + state := StateMutable + tv := New{{ .structName }}(&orig, &state) + FillTest{{ .structName }}(tv) + return tv +} + +func FillTest{{ .structName }}(tv {{ .structName }}) { + {{- range .fields }} + {{ .GenerateSetWithTestValue $.messageStruct }} + {{- end }} +} diff --git a/pdata/internal/cmd/pdatagen/internal/templates/message_test.go.tmpl b/pdata/internal/cmd/pdatagen/internal/templates/message_test.go.tmpl new file mode 100644 index 00000000000..ff96aa71718 --- /dev/null +++ b/pdata/internal/cmd/pdatagen/internal/templates/message_test.go.tmpl @@ -0,0 +1,54 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by "pdata/internal/cmd/pdatagen/main.go". DO NOT EDIT. +// To regenerate this file run "make genpdata". + +package {{ .packageName }} + +import ( +{{ range $index, $element := .testImports -}} +{{ $element }} +{{ end }} +) + +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) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.MoveTo(new{{ .structName }}(&{{ .originName }}{}, &sharedState)) }) + assert.Panics(t, func() { new{{ .structName }}(&{{ .originName }}{}, &sharedState).MoveTo(dest) }) +} + +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) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(new{{ .structName }}(&{{ .originName }}{}, &sharedState)) }) +} + +{{ range .fields }} +{{ .GenerateAccessorsTest $.messageStruct }} +{{ end }} + +{{- if not .isCommon }} +func generateTest{{ .structName }}() {{ .structName }} { + tv := New{{ .structName }}() + fillTest{{ .structName }}(tv) + return tv +} + +func fillTest{{ .structName }}(tv {{ .structName }}) { + {{- range .fields }} + {{ .GenerateSetWithTestValue $.messageStruct }} + {{- end }} +} +{{ end }} diff --git a/pdata/internal/cmd/pdatagen/internal/templates/primitive_slice.go.tmpl b/pdata/internal/cmd/pdatagen/internal/templates/primitive_slice.go.tmpl new file mode 100644 index 00000000000..c8b848a81f4 --- /dev/null +++ b/pdata/internal/cmd/pdatagen/internal/templates/primitive_slice.go.tmpl @@ -0,0 +1,110 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by "pdata/internal/cmd/pdatagen/main.go". DO NOT EDIT. +// To regenerate this file run "make genpdata". + +package {{ .packageName }} + +import ( +{{ range $index, $element := .imports -}} +{{ $element }} +{{ end }} +) + +// {{ .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. +// Important: zero-initialized instance is not valid for use. +type {{ .structName }} internal.{{ .structName }} + +func (ms {{ .structName }}) getOrig() *[]{{ .itemType }} { + return internal.GetOrig{{ .structName }}(internal.{{ .structName }}(ms)) +} + +func (ms {{ .structName }}) getState() *internal.State { + return internal.Get{{ .structName }}State(internal.{{ .structName }}(ms)) +} + +// New{{ .structName }} creates a new empty {{ .structName }}. +func New{{ .structName }}() {{ .structName }} { + orig := []{{ .itemType }}(nil) + state := internal.StateMutable + return {{ .structName }}(internal.New{{ .structName }}(&orig, &state)) +} + +// 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.getState().AssertMutable() + *ms.getOrig() = copy{{ .structName }}(*ms.getOrig(), val) +} + +// 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 }} { + return (*ms.getOrig())[i] +} + +// SetAt sets {{ .itemType }} item at particular index. +// Equivalent of {{ .lowerStructName }}[i] = val +func (ms {{ .structName }}) SetAt(i int, val {{ .itemType }}) { + ms.getState().AssertMutable() + (*ms.getOrig())[i] = val +} + +// 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) { + ms.getState().AssertMutable() + oldCap := cap(*ms.getOrig()) + if newCap <= oldCap { + return + } + + 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 }}) { + ms.getState().AssertMutable() + *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 }}) { + ms.getState().AssertMutable() + dest.getState().AssertMutable() + *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.getState().AssertMutable() + *dest.getOrig() = copy{{ .structName }}(*dest.getOrig(), *ms.getOrig()) +} + +func copy{{ .structName }}(dst, src []{{ .itemType }}) []{{ .itemType }} { + dst = dst[:0] + return append(dst, src...) +} diff --git a/pdata/internal/cmd/pdatagen/internal/templates/primitive_slice_internal.go.tmpl b/pdata/internal/cmd/pdatagen/internal/templates/primitive_slice_internal.go.tmpl new file mode 100644 index 00000000000..db8b2001546 --- /dev/null +++ b/pdata/internal/cmd/pdatagen/internal/templates/primitive_slice_internal.go.tmpl @@ -0,0 +1,42 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by "pdata/internal/cmd/pdatagen/main.go". DO NOT EDIT. +// To regenerate this file run "make genpdata". + +package internal + +import ( +{{ range $index, $element := .imports -}} +{{ if ne $element "go.opentelemetry.io/collector/pdata/internal" }} +{{ $element }} +{{ end }} +{{ end }} +) + +type {{ .structName }} struct { + orig *[]{{ .itemType }} + state *State +} + +func GetOrig{{ .structName }}(ms {{ .structName }}) *[]{{ .itemType }} { + return ms.orig +} + +func Get{{ .structName }}State(ms {{ .structName }}) *State { + return ms.state +} + +func New{{ .structName }}(orig *[]{{ .itemType }}, state *State) {{ .structName }} { + return {{ .structName }}{orig: orig, state: state} +} + +func FillTest{{ .structName }}(tv {{ .structName}}) { +} + +func GenerateTest{{ .structName }}() {{ .structName }} { + state := StateMutable + var orig []{{ .itemType }} = nil + + return {{ .structName }}{&orig, &state} +} diff --git a/pdata/internal/cmd/pdatagen/internal/templates/primitive_slice_test.go.tmpl b/pdata/internal/cmd/pdatagen/internal/templates/primitive_slice_test.go.tmpl new file mode 100644 index 00000000000..26f6038ba7c --- /dev/null +++ b/pdata/internal/cmd/pdatagen/internal/templates/primitive_slice_test.go.tmpl @@ -0,0 +1,113 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by "pdata/internal/cmd/pdatagen/main.go". DO NOT EDIT. +// To regenerate this file run "make genpdata". + +package {{ .packageName }} + +import ( +{{ range $index, $element := .testImports -}} +{{ $element }} +{{ end }} +) + +func TestNew{{ .structName }}(t *testing.T) { + ms := New{{ .structName }}() + assert.Equal(t, 0, ms.Len()) + ms.FromRaw([]{{ .itemType }}{ {{ .testOrigVal }} }) + assert.Equal(t, 3, ms.Len()) + assert.Equal(t, []{{ .itemType }}{ {{ .testOrigVal }} }, ms.AsRaw()) + ms.SetAt(1, {{ .itemType }}( {{ .testSetVal }} )) + assert.Equal(t, []{{ .itemType }}{ {{ .testNewVal }} }, ms.AsRaw()) + ms.FromRaw([]{{ .itemType }}{ {{ index .testInterfaceOrigVal 2 }} }) + assert.Equal(t, 1, ms.Len()) + {{- if eq .itemType "float64" }} + assert.InDelta(t, {{ .itemType }}({{ index .testInterfaceOrigVal 2 }}), ms.At(0), 0.01) + {{- else }} + assert.Equal(t, {{ .itemType }}({{ index .testInterfaceOrigVal 2 }}), ms.At(0)) + {{- end }} + + cp := New{{ .structName }}() + ms.CopyTo(cp) + ms.SetAt(0, {{ .itemType }}( {{ index .testInterfaceOrigVal 1 }} )) + {{- if eq .itemType "float64" }} + assert.InDelta(t, {{ .itemType }}({{ index .testInterfaceOrigVal 1 }}), ms.At(0), 0.01) + {{- else }} + assert.Equal(t, {{ .itemType }}({{ index .testInterfaceOrigVal 1 }}), ms.At(0)) + {{- end }} + {{- if eq .itemType "float64" }} + assert.InDelta(t, {{ .itemType }}({{ index .testInterfaceOrigVal 2 }}), cp.At(0), 0.01) + {{- else }} + assert.Equal(t, {{ .itemType }}({{ index .testInterfaceOrigVal 2 }}), cp.At(0)) + {{- end }} + ms.CopyTo(cp) + {{- if eq .itemType "float64" }} + assert.InDelta(t, {{ .itemType }}({{ index .testInterfaceOrigVal 1 }}), cp.At(0), 0.01) + {{- else }} + assert.Equal(t, {{ .itemType }}({{ index .testInterfaceOrigVal 1 }}), cp.At(0)) + {{- end }} + + mv := New{{ .structName }}() + ms.MoveTo(mv) + assert.Equal(t, 0, ms.Len()) + assert.Equal(t, 1, mv.Len()) + {{- if eq .itemType "float64" }} + assert.InDelta(t, {{ .itemType }}({{index .testInterfaceOrigVal 1 }}), mv.At(0), 0.01) + {{- else }} + assert.Equal(t, {{ .itemType }}({{index .testInterfaceOrigVal 1 }}), mv.At(0)) + {{- end }} + ms.FromRaw([]{{ .itemType }}{ {{ .testOrigVal }} }) + ms.MoveTo(mv) + assert.Equal(t, 3, mv.Len()) + {{- if eq .itemType "float64" }} + assert.InDelta(t, {{ .itemType }}({{index .testInterfaceOrigVal 0 }}), mv.At(0), 0.01) + {{- else }} + assert.Equal(t, {{ .itemType }}({{index .testInterfaceOrigVal 0 }}), mv.At(0)) + {{- end }} +} + +func Test{{ .structName }}ReadOnly(t *testing.T) { + raw := []{{ .itemType }}{ {{ .testOrigVal }}} + state := internal.StateReadOnly + ms := {{ .structName }}(internal.New{{ .structName }}(&raw, &state)) + + assert.Equal(t, 3, ms.Len()) + {{- if eq .itemType "float64" }} + assert.InDelta(t, {{ .itemType }}( {{index .testInterfaceOrigVal 0 }} ), ms.At(0), 0.01) + {{- else }} + assert.Equal(t, {{ .itemType }}({{ index .testInterfaceOrigVal 0 }}), ms.At(0)) + {{- end }} + assert.Panics(t, func() { ms.Append({{ index .testInterfaceOrigVal 0 }}) }) + assert.Panics(t, func() { ms.EnsureCapacity(2) }) + assert.Equal(t, raw, ms.AsRaw()) + assert.Panics(t, func() { ms.FromRaw(raw) }) + + ms2 := New{{ .structName }}() + ms.CopyTo(ms2) + assert.Equal(t, ms.AsRaw(), ms2.AsRaw()) + assert.Panics(t, func() { ms2.CopyTo(ms) }) + + assert.Panics(t, func() { ms.MoveTo(ms2) }) + assert.Panics(t, func() { ms2.MoveTo(ms) }) +} + +func Test{{ .structName }}Append(t *testing.T) { + ms := New{{ .structName }}() + ms.FromRaw([]{{ .itemType }}{ {{ .testOrigVal }} }) + ms.Append({{ .testSetVal }}, {{ .testSetVal }}) + assert.Equal(t, 5, ms.Len()) + {{- if eq .itemType "float64" }} + assert.InDelta(t, {{ .itemType }}({{ .testSetVal }} ), ms.At(4), 0.01) + {{- else }} + assert.Equal(t, {{ .itemType }}({{ .testSetVal }}), ms.At(4)) + {{- end }} +} + +func Test{{ .structName }}EnsureCapacity(t *testing.T) { + ms := New{{ .structName }}() + ms.EnsureCapacity(4) + assert.Equal(t, 4, cap(*ms.getOrig())) + ms.EnsureCapacity(2) + assert.Equal(t, 4, cap(*ms.getOrig())) +} diff --git a/pdata/internal/cmd/pdatagen/internal/templates/slice.go.tmpl b/pdata/internal/cmd/pdatagen/internal/templates/slice.go.tmpl new file mode 100644 index 00000000000..082c6c18cce --- /dev/null +++ b/pdata/internal/cmd/pdatagen/internal/templates/slice.go.tmpl @@ -0,0 +1,163 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by "pdata/internal/cmd/pdatagen/main.go". DO NOT EDIT. +// To regenerate this file run "make genpdata". + +package {{ .packageName }} + +import ( +{{ range $index, $element := .imports -}} +{{ $element }} +{{ end }} +) + +// {{ .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. +// Important: zero-initialized instance is not valid for use. +type {{ .structName }} struct { + orig *[]{{ .originElementType }} + state *internal.State +} + +func new{{ .structName }}(orig *[]{{ .originElementType }}, state *internal.State) {{ .structName }} { + return {{ .structName }}{orig: orig, state: state} +} + +// New{{ .structName }} creates a {{ .structName }} with 0 elements. +// Can use "EnsureCapacity" to initialize with a given capacity. +func New{{ .structName }}() {{ .structName }} { + orig := []{{ .originElementType }}(nil) + state := internal.StateMutable + return new{{ .structName }}(&orig, &state) +} + +// Len returns the number of elements in the slice. +// +// Returns "0" for a newly instance created with "New{{ .structName }}()". +func (es {{ .structName }}) Len() int { + return len(*es.orig) +} + +// At returns the element at the given index. +// +// This function is used mostly for iterating over all the values in the slice: +// for i := 0; i < es.Len(); i++ { +// e := es.At(i) +// ... // Do something with the element +// } +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 }}() +// 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) { + es.state.AssertMutable() + oldCap := cap(*es.orig) + if newCap <= oldCap { + return + } + + 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.state.AssertMutable() + *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 }}) { + es.state.AssertMutable() + dest.state.AssertMutable() + if *dest.orig == nil { + // We can simply move the entire vector and avoid any allocations. + *dest.orig = *es.orig + } else { + *dest.orig = append(*dest.orig, *es.orig...) + } + *es.orig = nil +} + +// 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) { + es.state.AssertMutable() + newLen := 0 + for i := 0; i < len(*es.orig); i++ { + if f(es.At(i)) { + continue + } + if newLen == i { + // Nothing to move, element is at the right place. + newLen++ + continue + } + (*es.orig)[newLen] = (*es.orig)[i] + newLen++ + } + *es.orig = (*es.orig)[:newLen] +} + + +// CopyTo copies all elements from the current slice overriding the destination. +func (es {{ .structName }}) CopyTo(dest {{ .structName }}) { + dest.state.AssertMutable() + 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], es.state).CopyTo(new{{ .elementName }}((*dest.orig)[i], dest.state)) + } + return + } + origs := make([]{{ .originName }}, srcLen) + wrappers := make([]*{{ .originName }}, srcLen) + for i := range *es.orig { + wrappers[i] = &origs[i] + new{{ .elementName }}((*es.orig)[i], es.state).CopyTo(new{{ .elementName }}(wrappers[i], dest.state)) + } + *dest.orig = wrappers + + {{- else }} + } else { + (*dest.orig) = make([]{{ .originElementType }}, srcLen) + } + for i := range *es.orig { + {{ .newElement }}.CopyTo(new{{ .elementName }}(&(*dest.orig)[i], dest.state)) + } + {{- 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) { + es.state.AssertMutable() + sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) +} +{{ end }} diff --git a/pdata/internal/cmd/pdatagen/internal/templates/slice_test.go.tmpl b/pdata/internal/cmd/pdatagen/internal/templates/slice_test.go.tmpl new file mode 100644 index 00000000000..8b947a5ac8b --- /dev/null +++ b/pdata/internal/cmd/pdatagen/internal/templates/slice_test.go.tmpl @@ -0,0 +1,152 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by "pdata/internal/cmd/pdatagen/main.go". DO NOT EDIT. +// To regenerate this file run "make genpdata". + +package {{ .packageName }} + +import ( +{{ range $index, $element := .testImports -}} +{{ $element }} +{{ end }} +) + +func Test{{ .structName }}(t *testing.T) { + es := New{{ .structName }}() + assert.Equal(t, 0, es.Len()) + state := internal.StateMutable + es = new{{ .structName }}(&[]{{ .originElementType }}{}, &state) + assert.Equal(t, 0, es.Len()) + + 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) + assert.Equal(t, testVal, es.At(i)) + } + assert.Equal(t, 7, es.Len()) +} + +func Test{{ .structName }}ReadOnly(t *testing.T) { + sharedState := internal.StateReadOnly + es := new{{ .structName }}(&[]{{ .originElementType }}{}, &sharedState) + assert.Equal(t, 0, es.Len()) + assert.Panics(t, func() { es.AppendEmpty() }) + assert.Panics(t, func() { es.EnsureCapacity(2) }) + es2 := New{{ .structName }}() + es.CopyTo(es2) + assert.Panics(t, func() { es2.CopyTo(es) }) + assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) + assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) +} + +func Test{{ .structName }}_CopyTo(t *testing.T) { + dest := New{{ .structName }}() + // Test CopyTo to empty + New{{ .structName }}().CopyTo(dest) + assert.Equal(t, New{{ .structName }}(), dest) + + // Test CopyTo larger slice + 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) +} + +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) + + // Test ensure larger capacity + const ensureLargeLen = 9 + es.EnsureCapacity(ensureLargeLen) + assert.Less(t, generateTest{{ .structName }}().Len(), ensureLargeLen) + assert.Equal(t, ensureLargeLen, cap(*es.orig)) + assert.Equal(t, generateTest{{ .structName }}(), es) +} + +func Test{{ .structName }}_MoveAndAppendTo(t *testing.T) { + // Test MoveAndAppendTo to empty + expectedSlice := generateTest{{ .structName }}() + dest := New{{ .structName }}() + src := generateTest{{ .structName }}() + src.MoveAndAppendTo(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, 0, src.Len()) + assert.Equal(t, expectedSlice.Len(), dest.Len()) + + // Test MoveAndAppendTo not empty slice + 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)) + assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) + } +} + +func Test{{ .structName }}_RemoveIf(t *testing.T) { + // Test RemoveIf on empty slice + emptySlice := New{{ .structName }}() + emptySlice.RemoveIf(func(el {{ .elementName }}) bool { + t.Fail() + return false + }) + + // Test RemoveIf + filtered := generateTest{{ .structName }}() + pos := 0 + filtered.RemoveIf(func(el {{ .elementName }}) bool { + pos++ + return pos%3 == 0 + }) + assert.Equal(t, 5, filtered.Len()) +} + +{{ 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.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) + } + 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.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) + } +} +{{- end }} + +func generateTest{{ .structName }}() {{ .structName }} { + es := New{{ .structName }}() + fillTest{{ .structName }}(es) + return es +} + +func fillTest{{ .structName }}(es {{ .structName }}) { + *es.orig = make([]{{ .originElementType }}, 7) + for i := 0; i < 7; i++ { + (*es.orig)[i] = {{ .emptyOriginElement }} + fillTest{{ .elementName }}({{ .newElement }}) + } +}