Skip to content

Commit

Permalink
Merge pull request #87 from jmattheis/dont-copy
Browse files Browse the repository at this point in the history
  • Loading branch information
jmattheis authored Sep 10, 2023
2 parents 9f096d2 + 316b8ea commit a1ae13d
Show file tree
Hide file tree
Showing 13 changed files with 192 additions and 45 deletions.
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@ use reflection.
## Features

- **Fast execution**: No reflection is used at runtime
- Automatically [deep
copies](https://en.wikipedia.org/wiki/Object_copying#Deep_copy) builtin
types: slices, maps, named types, primitive types, pointers, structs with
same fields
- Automatically converts builtin types: slices, maps, named types, primitive
types, pointers, structs with same fields
- [Deep copies](https://en.wikipedia.org/wiki/Object_copying#Deep_copy) per
default and supports [shallow
copying](https://en.wikipedia.org/wiki/Object_copying#Shallow_copy)
- **Customizable**: [You can implement custom converter methods](https://goverter.jmattheis.de/#/conversion/custom)
- [Clear errors when generating the conversion methods](https://goverter.jmattheis.de/#/conversion/?id=error-early) if
- the target struct has unmapped fields
Expand Down Expand Up @@ -86,7 +87,7 @@ use reflection.
1. Run `goverter`:

```bash
$ go run github.com/jmattheis/goverter/cmd/goverter@v0.17.4 ./
$ go run github.com/jmattheis/goverter/cmd/goverter@v0.18.0 ./
```

See [Installation](https://goverter.jmattheis.de/#/install) for more information.
Expand Down
1 change: 1 addition & 0 deletions builder/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const (
FlagMatchIgnoreCase
FlagIgnoreUnexported
FlagZeroValueOnPtrInconsistency
FlagSkipCopySameType
)

type ConversionFlags map[ConversionFlag]bool
Expand Down
19 changes: 19 additions & 0 deletions builder/skipcopy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package builder

import (
"github.com/dave/jennifer/jen"
"github.com/jmattheis/goverter/xtype"
)

// SkipCopy handles FlagSkipCopySameType.
type SkipCopy struct{}

// Matches returns true, if the builder can create handle the given types.
func (*SkipCopy) Matches(ctx *MethodContext, source, target *xtype.Type) bool {
return ctx.Flags.Has(FlagSkipCopySameType) && source.T.String() == target.T.String()
}

// Build creates conversion source code for the given source and target type.
func (*SkipCopy) Build(_ Generator, _ *MethodContext, sourceID *xtype.JenID, _, _ *xtype.Type) ([]jen.Code, *xtype.JenID, *Error) {
return nil, sourceID, nil
}
6 changes: 6 additions & 0 deletions comments/parse_docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,9 @@ func parseConverterComment(comment string, config ConverterConfig) (ConverterCon
case "ignoreMissing":
config.Flags.Set(builder.FlagIgnoreMissing)
continue
case "skipCopySameType":
config.Flags.Set(builder.FlagSkipCopySameType)
continue
case "useZeroValueOnPointerInconsistency":
config.Flags.Set(builder.FlagZeroValueOnPtrInconsistency)
continue
Expand Down Expand Up @@ -318,6 +321,9 @@ func parseMethodComment(comment string) (Method, error) {
case "useZeroValueOnPointerInconsistency":
m.Flags.Set(builder.FlagZeroValueOnPtrInconsistency)
continue
case "skipCopySameType":
m.Flags.Set(builder.FlagSkipCopySameType)
continue
case "wrapErrors":
if strings.TrimSpace(remaining) != "" {
return m, fmt.Errorf("invalid %s:wrapErrors, parameters not supported", prefix)
Expand Down
51 changes: 51 additions & 0 deletions docs/conversion/misc.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,54 @@ func (c *ConverterImpl) Convert(source example.Input) example.Output {
```

<!-- tabs:end -->

## Skip copy same type

Goverter deep copies instances when converting the source to the target type.
With `goverter:skipCopySameType` you instruct Goverter to skip copying
instances when the source and target type is the same.

The setting can be enabled on both the converter interface and methods.

<!-- tabs:start -->

#### **input.go**

```go
package example

// goverter:converter
// goverter:skipCopySameType
type Converter interface {
Convert(source Input) Output
}

type Input struct {
Name *string
ItemCounts map[string]int
}

type Output struct {
Name *string
ItemCounts map[string]int
}
```

#### **generated/generated.go**

```go
package generated

import example "goverter/example"

type ConverterImpl struct{}

func (c *ConverterImpl) Convert(source example.Input) example.Output {
var exampleOutput example.Output
exampleOutput.Name = source.Name
exampleOutput.ItemCounts = source.ItemCounts
return exampleOutput
}
```

<!-- tabs:end -->
1 change: 1 addition & 0 deletions generator/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type Config struct {

// BuildSteps that'll used for generation.
var BuildSteps = []builder.Builder{
&builder.SkipCopy{},
&builder.BasicTargetPointerRule{},
&builder.Pointer{},
&builder.SourcePointer{},
Expand Down
3 changes: 3 additions & 0 deletions generator/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,9 @@ func (g *generator) Build(
case source.Pointer && source.PointerInner.Named && !source.PointerInner.Basic:
createSubMethod = true
}
if ctx.Flags.Has(builder.FlagSkipCopySameType) && source.T.String() == target.T.String() {
createSubMethod = false
}
}
ctx.MarkSeen(source)

Expand Down
40 changes: 0 additions & 40 deletions scenario/generic_go16.yml

This file was deleted.

File renamed without changes.
File renamed without changes.
19 changes: 19 additions & 0 deletions scenario/skipcopy_identity.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
input:
input.go: |
package skip
// goverter:converter
// goverter:skipCopySameType
type Converter interface {
Convert(source map[string]int) map[string]int
}
success: |
// Code generated by github.com/jmattheis/goverter, DO NOT EDIT.
package generated
type ConverterImpl struct{}
func (c *ConverterImpl) Convert(source map[string]int) map[string]int {
return source
}
56 changes: 56 additions & 0 deletions scenario/skipcopy_inner.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
input:
input.go: |
package skip
import "time"
// goverter:converter
// goverter:skipCopySameType
type Converter interface {
Convert(source Input) Output
}
type Input struct {
ID *int
Map map[string]int
MapDifferentType map[string]int
CreatedAt time.Time
Unnamed struct{Name string}
}
type Output struct {
ID *int
Map map[string]int
MapDifferentType map[string]ID
CreatedAt *time.Time
Unnamed struct{Name string}
}
type ID int
success: |
// Code generated by github.com/jmattheis/goverter, DO NOT EDIT.
package generated
import (
execution "github.com/jmattheis/goverter/execution"
"time"
)
type ConverterImpl struct{}
func (c *ConverterImpl) Convert(source execution.Input) execution.Output {
var skipOutput execution.Output
skipOutput.ID = source.ID
skipOutput.Map = source.Map
mapStringSkipID := make(map[string]execution.ID, len(source.MapDifferentType))
for key, value := range source.MapDifferentType {
mapStringSkipID[key] = execution.ID(value)
}
skipOutput.MapDifferentType = mapStringSkipID
skipOutput.CreatedAt = c.timeTimeToPTimeTime(source.CreatedAt)
skipOutput.Unnamed = source.Unnamed
return skipOutput
}
func (c *ConverterImpl) timeTimeToPTimeTime(source time.Time) *time.Time {
return &source
}
30 changes: 30 additions & 0 deletions scenario/skipcopy_method.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
input:
input.go: |
package skip
// goverter:converter
type Converter interface {
// goverter:skipCopySameType
Convert(source Input) Output
}
type Input struct {
ID *int
}
type Output struct {
ID *int
}
success: |
// Code generated by github.com/jmattheis/goverter, DO NOT EDIT.
package generated
import execution "github.com/jmattheis/goverter/execution"
type ConverterImpl struct{}
func (c *ConverterImpl) Convert(source execution.Input) execution.Output {
var skipOutput execution.Output
skipOutput.ID = source.ID
return skipOutput
}

0 comments on commit a1ae13d

Please sign in to comment.