Skip to content

generate code for struct conversion/copy in go

Notifications You must be signed in to change notification settings

ycl2018/go-conv

Repository files navigation

go-conv

Build Status Go Report Card

Automatically generate conversion code based on function type declarations, supporting conversion/deep copy modes, and custom conversion functions/filters/ignore specific fields and other options.

Features

  • Support conv/deepCopy modes
  • Support generics
  • Support automatic pointer resolution
  • Support basic types/map/slice/array/struct conversion
  • Support automatic upcasting of basic types
  • Support Alias type automatic conversion
  • Support embed field automatic unpacking
  • Support self-referencing objects, support recursive conversion
  • Automatically handle naming conflicts in the same package
  • Support string <-> []byte/[]rune conversion
  • Support Pointer <-> Struct conversion
  • Support Array <-> Slice conversion
  • Support extended custom conversion/filter/ignore options

Example

Generation command:

go run github.com/ycl2018/go-conv@latest./...

conv mode

The conv mode is the default type conversion mode, which uses shallow copy to improve conversion performance.

// go-conv:generate
var Foo2Bar func (src *Foo) *Bar

type Foo struct {
    Str     string
    Slice   []string
    Map     map[string]string
    Pointer string
    Alias   string
}

type Bar struct {
    Str     string
    Slice   []string
    Map     map[string]string
    Pointer *string
    Alias   StringAlias
}

type StringAlias string

generated:

// Code generated by github.com/ycl2018/go-conv DO NOT EDIT.

package testdata

func FooToBar(src *Foo) (dst *Bar) {
    if src!= nil {
        dst = new(Bar)
        dst.Str = src.Str
        dst.Slice = src.Slice
        dst.Map = src.Map
        dst.Pointer = &src.Pointer
        dst.Alias = (StringAlias)(src.Alias)
    }
    return
}
func init() {
    Foo2Bar = FooToBar
}

copy mode

The copy mode uses a deep copy mode to copy each field of the structure.

// go-conv:generate
// go-conv:copy
var Foo2Bar func(src *Foo) *Bar

type Foo struct {
    Str     string
    Slice   []string
    Map     map[string]string
    Pointer string
    Alias   string
}

type Bar struct {
    Str     string
    Slice   []string
    Map     map[string]string
    Pointer *string
    Alias   StringAlias
}

type StringAlias string

generated:

// Code generated by github.com/ycl2018/go-conv DO NOT EDIT.

package example

func CopyPtrFooToPtrBar(src *Foo) (dst *Bar) {
    if src!= nil {
        dst = new(Bar)
        dst.Str = src.Str
        if len(src.Slice) > 0 {
            dst.Slice = make([]string, len(src.Slice))
            for i := 0; i < len(src.Slice); i++ {
                dst.Slice[i] = src.Slice[i]
            }
        }
        if len(src.Map) > 0 {
            dst.Map = make(map[string]string, len(src.Map))
            for k, v := range src.Map {
                var tmpK string
                var tmpV string
                tmpK = k
                tmpV = v
                dst.Map[tmpK] = tmpV
            }
        }
        dst.Pointer = new(string)
        *dst.Pointer = src.Pointer
        dst.Alias = StringAlias(src.Alias)
    }
    return
}
func init() {
    Foo2Bar = CopyPtrFooToPtrBar
}

Extension options

You can use go-conv:apply to specify the configuration to be applied, which is programmatically IDE-friendly and more convenient to configure.

package cases

import (
    "strconv"

    "github.com/ycl2018/go-conv/option"
    "github.com/ycl2018/go-conv/testdata/a"
    "github.com/ycl2018/go-conv/testdata/b"
)

// Struct2Struct conv a Basic to b Basic
// go-conv:generate
// go-conv:apply basicConvOpts
var Struct2Struct func(p *a.Struct) *b.Struct


var basicConvOpts = []option.Option{
    option.WithIgnoreFields(a.Struct{}, []string{"Pojo"}),
    option.WithIgnoreTypes(a.Student{}, "Student3"),
    option.WithTransformer(transfer, "Student2.Class.Grade"),
    option.WithFilter(filter, "Student2.Teachers"),
    option.WithFieldMatch(a.Struct{}, map[string]string{
        "Match": "Match_",
    }),
    option.WithMatchCaseInsensitive(),
    option.WithNoInitFunc(),
}

func transfer(t int) string {
    return strconv.Itoa(t)
}

func filter(arr []string) []string {
    return arr
}
// Code generated by github.com/ycl2018/go-conv DO NOT EDIT.

package cases

import (
    "github.com/ycl2018/go-conv/testdata/a"
    "github.com/ycl2018/go-conv/testdata/b"
)

func PtrAStructToPtrBStruct(src *a.Struct) (dst *b.Struct) {
    if src!= nil {
        dst = new(b.Struct)
        dst.Student.Name = src.Student.Name
        dst.Student.Class.Name = src.Student.Class.Name
        dst.Student.Class.Grade = string(src.Student.Class.Grade)
        dst.Student.Teachers = src.Student.Teachers
        dst.Student2.Name = src.Student2.Name
        dst.Student2.Class.Name = src.Student2.Class.Name
        // apply transfer option on transfer
        transferredSrcStudent2ClassGrade := transfer(src.Student2.Class.Grade)
        dst.Student2.Class.Grade = transferredSrcStudent2ClassGrade
        // apply filter option on filter
        filteredSrcStudent2Teachers := filter(src.Student2.Teachers)
        dst.Student2.Teachers = filteredSrcStudent2Teachers
        // apply ignore option on src.Student3
        // apply ignore option on src.Pojo
        dst.Match_ = src.Match
        dst.Caseinsensitive = src.CaseInsensitive
    }
    return
}

for More usage examples please refer to the testdata directory

Releases

No releases published

Languages